簡體   English   中英

使用SHA256withRSA簽名后如何驗證signatureBytes?

[英]How to verify signatureBytes after signing it with SHA256withRSA?

我正在使用“ 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. 但是我不知道帶有私鑰的驗證提供者。

您的代碼有幾個問題:

  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)); 

你在這里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);
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);

使用摘要SHA256RSA對某些文本/數據簽名后,請檢查此完整且有效的代碼以驗證簽名

/* 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM