如何在使用SHA256withRSA签名后验证signatureBytes?

时间:2015-01-20 10:07:32

标签: java cryptography digital-signature keystore public-key-encryption

我正在使用" Windows-MY"来签署一些文字。 KeyStore。 我想使用我的私钥进行签名并使用公钥进行验证。

KeyStore keyStore = KeyStore.getInstance("Windows-MY");
                keyStore.load(null, null); 
Enumeration en = keyStore.aliases();
while (en.hasMoreElements()) {   
    KeyStore keyStore = KeyStore.getInstance("Windows-MY");
                keyStore.load(null, null);
    String alias = en.nextElement().toString();
    X509Certificate c = (X509Certificate) keyStore.getCertificate(alias);
    String serialNumber = c.getSerialNumber().toString();
    System.out.println("--" + aliasName);
                PrivateKey privateKey = (PrivateKey) keyStore.getKey(aliasName, null);
                PublicKey publicKey = (PublicKey) c.getPublicKey();
                Certificate[] chain = keyStore.getCertificateChain(aliasName);
    DataOutputStream fout = new DataOutputStream(outstream);
    // -------------------------------------------------------
    String data = "Monika";
    byte[] content = data.getBytes();
    Provider p = keyStore.getProvider();
    // ----------------------signature---start---------------------------

    Signature signature = Signature.getInstance("SHA256withRSA", p);
    System.out.println(" signature.getProvider():"+ signature.getProvider());
    signature.initSign(privateKey);
    signature.update(content);
    byte[] signatureBytes = signature.sign();
    System.out.println("signatureBytes-------------"+ signatureBytes.toString());
    // ----------------------signature----------end------------------

    // ------------------------verification---------------
    Signature signature1 = Signature.getInstance("SHA256withRSA", p);
    System.out.println(" signature1.getProvider():"+ signature1.getProvider());
    signature1.initVerify(publicKey);
    signature1.update(content);
    boolean verifies = signature1.verify(signatureBytes);
    System.out.println("signature verifies: " + verifies);
    // ------------------------------------------------
    fout.close();
} // while

输出:

privateKey:RSAPrivateKey [size=2048 bits, type=Exchange, container=AC0BEBA9-A361-4611-96D9-B365B671FBC3]
 signature.getProvider():SunMSCAPI version 1.6
signatureBytes-------------[B@1402d5a
 signature1.getProvider():SunRsaSign version 1.5
signature verifies: false

请注意:

  1. 我的私钥已经是RSAPrivateKey。
  2. 签名提供商是SunMSCAPI。
  3. 但我不知道使用PrivateKey验证提供程序。

4 个答案:

答案 0 :(得分:3)

您的代码存在以下问题:

  1. 您只是使用Windows密钥库中的第一个证书/公钥。这可能实际上是正确的,但在密钥库中可能有多个证书,然后只是巧合用于验证的证书。

    String alias = en.nextElement().toString();
    X509Certificate c = (X509Certificate) keyStore.getCertificate(alias);
    PublicKey publicKey = c.getPublicKey();
    PrivateKey privateKey = (PrivateKey) keyStore.getKey(DSCName, null);
    

    您应该写keyStore.getCertificate(DSCName)以确保它与私钥匹配。

  2. 您正在无缘无故地生成密钥(分别尝试转换现有密钥)。您可以完全删除此代码。这也将解决您的NullPointerException问题:

    byte[] encodedPrivateKey = privateKey.getEncoded();
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
    RSAPrivateKey privateKey1 = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    
  3. 您的问题中有很多不必要的代码,例如加载证书链,但从不使用它。这使得修复变得更加困难。最小(工作)示例如下所示:

    String alias = "myAlias";
    String myData = "data to encrypt";
    
    KeyStore keyStore = KeyStore.getInstance("Windows-MY");
    keyStore.load(null, null);
    
    X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
    PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, null);
    PublicKey publicKey = cert.getPublicKey();
    
    Signature instance = Signature.getInstance("SHA256withRSA");
    instance.initSign(privateKey, new SecureRandom());
    instance.update(myData.getBytes("UTF-8"));
    byte[] signedBytes = instance.sign();
    
    instance.initVerify(publicKey);
    instance.update(myData.getBytes("UTF-8"));
    System.out.println(instance.verify(signedBytes));
    

答案 1 :(得分:1)

您在这里获得null

byte[] encodedPrivateKey = privateKey.getEncoded(); // are you sure that this byte array is not null ?

为了让事情更安全,请点击此处:

 PrivateKey privateKey = (PrivateKey) keyStore.getKey(
                    DSCName, null); // this maybe returning null

所以在给出错误的行之前,请进行检查:

if(encodedPrivateKey==null){
    System.out.println("private key is null");
}               
 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(
                    encodedPrivateKey);

答案 2 :(得分:0)

Signature signature = Signature.getInstance("SHA256withRSA",p);
                        System.out.println(" signature.getProvider():"+ signature.getProvider());
                        signature.initSign(privateKey, new SecureRandom());
                        signature.update(byteData);
                        byte[] signatureBytes = signature.sign();




//                      X509Certificate cert1 =signatureBytes. 
                        System.out.println("signatureBytes-------------"+ signatureBytes.toString());
                        // ----------------------signature----------end------------------

                        // ------------------------verification---------------
                        Signature signature1 = Signature.getInstance("SHA256withRSA");
                        System.out.println(" signature1.getProvider():"+ signature1.getProvider());
                        signature1.initVerify(publicKey);
                        signature1.update(byteData);

                        boolean verifies = signature1.verify(signatureBytes);
                        System.out.println("signature verifies: " + verifies);

答案 3 :(得分:0)

使用摘要 SHA256 RSA 签署一些文本/数据后,检查此完整且有效的代码以验证签名

/* verifyRSAsha256.java */
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import javax.xml.bind.DatatypeConverter;

/*
Compile:
clear && javac verifyRSAsha256.java && java verifyRSAsha256

Create private key:
openssl genrsa -des3 -out encrypted.pem 2048 && openssl rsa -in encrypted.pem -out private.pem -outform PEM && openssl rsa -in private.pem -pubout > public.pem

Create signature:
/bin/echo -n "some text that you want to be trusted" > data.txt
openssl dgst -sha256 -sign private.pem data.txt > signature.tmp
base64 signature.tmp

Verify signature:
openssl dgst -sha256 -verify public.pem -signature signature.tmp data.txt
*/

public class verifyRSAsha256 {

    public static void main(String args[]){
        String publicKey = 
        //  "-----BEGIN PUBLIC KEY-----"+
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwns0JWYgEshlpLYsZQFc"+
            "d5iVSqIHDO0zISLlO1aK4bbbosSvRE81+inKrG5mlnkIrv0+mJ/qTLY1RdBAVAe4"+
            "GPLTpHmLJhEtq7stydm2cCTEPRwfJNjoHqATDHEm1KLVGA8k0hztfMr8fLChE3/K"+
            "n2MHxzs7qhMLyBdPqbVC9RNja3i+Nl814xPTSXJ50zdJMLC56VtIU0xjqNjXN8iQ"+
            "pLZ2EfcP55nZ/venD01yxfsUn4sQLFTAlXqygA10fdDv9y0eZvgaGGSb4MuPT7yD"+
            "BfgNEU3tl4nRdSzPNkCkCmkuaa/pqZ5uw+G0HBwaQlHDwsnIcwE/xo6aHpt4xF4W"+
            "/QIDAQAB";
        //  "-----END PUBLIC KEY-----";

        byte[] signature, data;

        // the signature is a binary data and I encoded it with base64, so the signature must be decoded from base64 to binary again
        signature = DatatypeConverter.parseBase64Binary("Yy9CdQDfdYWwZkSu2SZgoFABHk5Bd3tzYvX73QR+GDCWpUsWrO5CXRF+j3dBz+bq1SRQ+1c1hdez5mMeE1587s4Mos8EsT1sqNemu4l4535P+jYicwG1m2MAesquAHhIIAyY9iGID576ehX0/34rCCeGuVZablpL+2ki6cEwxPVlH7xtWNIc1AdxivHjkWorkWC1LrbfcNdbZhUrNuz7DZsxHP2sr+2TQdD4L9CA2bgpj6HeQt+MTfCf2PKSdVoLFdwnM8638jHL6MVcEJxeIow/YUDZGEAyR743RdRk4CGU1bJ7er9M1Q4hFfYWGOBsLBok2XXUJcchLgWET1eKdA==");

        // the signature length have to be 256 bytes
        System.out.print("Signature length 256 = ");
        System.out.println(signature.length);

        // the data used the generate the signature
        data = "some text that you want to be trusted".getBytes();

        // verify if signature is ok
        try {System.out.println(verify(data,signature,publicKey));}catch(GeneralSecurityException e){e.printStackTrace();}

        // if any byte of data changes (ex: change last byte from d to D)
        data = "some text that you want to be trusteD".getBytes();

        // the signature doesn't math and method verify will fail
        try {System.out.println(verify(data,signature,publicKey));}catch(GeneralSecurityException e){e.printStackTrace();}

    }

    private static boolean verify(byte[] data, byte[] signature, String publicKey) throws GeneralSecurityException{
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(publicKey));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initVerify(pubKey);
        sig.update(data);
        return sig.verify(signature);
    }
}

您可以使用openssl命令行工具创建私钥和公钥:

openssl genrsa -des3 -out encrypted.pem 2048 
openssl rsa -in encrypted.pem -out private.pem -outform PEM
openssl rsa -in private.pem -pubout > public.pem

您可以使用openssl命令行工具使用私钥创建一个签名:

/bin/echo -n "some text that you want to be trusted" > data.txt
openssl dgst -sha256 -sign private.pem data.txt > signature.tmp

您可以使用openssl命令行工具验证签名是否正确:

openssl dgst -sha256 -verify public.pem -signature signature.tmp data.txt