关于x509certificate:使用数字签名验证签名哈希

Verifying Signed Hash using Digital Signature

我正在实现一个以三件事为输入的接口

  • X509证书

  • 用该证书的私钥签名的SignedHash

  • 初始哈希

  • 它必须执行以下操作:

  • 确认此哈希是使用提供的证书签名的。
  • 使用提供的证书的公钥作为输入对签名哈希进行解密,并检查其是否与提供的哈希匹配。
  • 我已实施以下验证数字签名的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
     public static boolean verifySignedHash(String X509Certificate, String hash,
                String signedHash) {

            boolean isVerified = false;

            ByteArrayInputStream inputStream = null;
            ByteArrayOutputStream outputStream = null;
            ByteArrayOutputStream byo = null;


            try {

                outputStream = new ByteArrayOutputStream();

                byte[] data = Base64.decodeBase64(X509Certificate);

                /* writing decoded X509 certificate to the ByteArrayOutputStream */

                outputStream.write(data);

                byte[] inp = outputStream.toByteArray();
                inputStream = new ByteArrayInputStream(inp);

                /* Getting the certificate from the Input */

                CertificateFactory cf = CertificateFactory.getInstance("X.509");

                X509Certificate certs = (X509Certificate) cf
                        .generateCertificate(inputStream);

                /* import encoded public key */

                X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(certs
                        .getPublicKey().getEncoded());

                /* Instantiating KeyFactory for accesing the Keys as Object */

                KeyFactory keyFactory = KeyFactory.getInstance("RSA");

                /*
                 * using the KeyFactory object to generate a PublicKey from the key
                 * specification.
                 */

                publickKey = keyFactory.generatePublic(pubKeySpec);

                byte[] signHash = Base64.decodeBase64(signedHash);

                byo = new ByteArrayOutputStream();

                byo.write(signHash);

                byte[] signChar = byo.toByteArray();

                ByteArrayInputStream byi = new ByteArrayInputStream(signChar);

                /* Next, input the signature bytes from the file specified */

                byte[] sigToVerify = new byte[byi.available()];
                byi.read(sigToVerify);
                byi.close();

                /* Instantiating Signature */
                Signature signature = Signature.getInstance(certs.getSigAlgName());

                /* Initializing the Public Key in Signature */

                signature.initVerify(publickKey);

                /* Supply the Signature Object With the Data to be Verified */

                BufferedInputStream bufin = new BufferedInputStream(byi);

                byte[] buffer = new byte[1024];
                int len;
                while (bufin.available() != 0) {
                    len = bufin.read(buffer);
                    signature.update(buffer, 0, len);
                };

                bufin.close();

                /* Verify the Signature */

                isVerified = signature.verify(sigToVerify);

            } catch (Exception e) {
                System.err.println("Caught exception" + e.toString());
            }

            return isVerified;
        }

    我得到的结果是错误的

    1
    **Am i Missing something or is this piece of code correct ?**

    我非常感谢你的帮助。谢谢。


    我复制了原始代码并将我的注释放入代码中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    // X509Certificate is class name, it cannot be variable name
    public static boolean verifySignedHash(String X509Certificate, String hash,
            String signedHash) {

        // Java is not C89 you don't have to declare variables in the beginning
        // of function, this reduces readability of the code and allows misuse
        boolean isVerified = false;

        ByteArrayInputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        ByteArrayOutputStream byo = null;

        try {

            outputStream = new ByteArrayOutputStream();

            byte[] data = Base64.decodeBase64(X509Certificate);

            /* writing decoded X509 certificate to the ByteArrayOutputStream */

            outputStream.write(data);

            byte[] inp = outputStream.toByteArray();

            // at this point inp is the same array as data, this makes no sence
            // and reduce performance

            inputStream = new ByteArrayInputStream(inp);

            /* Getting the certificate from the Input */

            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            X509Certificate certs = (X509Certificate) cf
                    .generateCertificate(inputStream);

            /* import encoded public key */
            // certs.getPublicKey() returns publicKey immediately, why to do
            // all these conversions?

            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(certs
                    .getPublicKey().getEncoded());

            /* Instantiating KeyFactory for accesing the Keys as Object */

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            /*
             * using the KeyFactory object to generate a PublicKey from the key
             * specification.
             */

            publickKey = keyFactory.generatePublic(pubKeySpec);

            byte[] signHash = Base64.decodeBase64(signedHash);

            byo = new ByteArrayOutputStream();

            byo.write(signHash);

            byte[] signChar = byo.toByteArray();

            // Again, signChar is the same as signHash, why would you do that?

            ByteArrayInputStream byi = new ByteArrayInputStream(signChar);

            /* Next, input the signature bytes from the file specified */

            byte[] sigToVerify = new byte[byi.available()];
            byi.read(sigToVerify);
            byi.close();

            // And now sigToVerify is the same as signChar and signHash.

            /* Instantiating Signature */
            Signature signature = Signature.getInstance(certs.getSigAlgName());

            /* Initializing the Public Key in Signature */

            signature.initVerify(publickKey);

            /* Supply the Signature Object With the Data to be Verified */

            // byi is already closed, you will get java.io.IOException: Stream closed
            BufferedInputStream bufin = new BufferedInputStream(byi);

            byte[] buffer = new byte[1024];
            int len;
            while (bufin.available() != 0) {
                len = bufin.read(buffer);
                signature.update(buffer, 0, len);
                // Any way bufin contained signature, while you need feed
                // plaintext to signature.update()
                // I could assume unused parameter hash has something to do
                // with plaintext
            };

            bufin.close();

            /* Verify the Signature */

            isVerified = signature.verify(sigToVerify);

        } catch (Exception e) {
            System.err.println("Caught exception" + e.toString());
        }

        return isVerified;
    }