簡體   English   中英

如何驗證私鑰是否與證書匹配..?

[英]How to verify if the private key matches with the certificate..?

我將私鑰存儲為.key文件..

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQD5YBS6V3APdgqaWAkijIUHRK4KQ6eChSaRWaw9L/4u8o3T1s8J
rUFHQhcIo5LPaQ4BrIuzHS8yzZf0m3viCTdZAiDn1ZjC2koquJ53rfDzqYxZFrId
7a4QYUCvM0gqx5nQ+lw1KoY/CDAoZN+sO7IJ4WkMg5XbgTWlSLBeBg0gMwIDAQAB
AoGASKDKCKdUlLwtRFxldLF2QPKouYaQr7u1ytlSB5QFtIih89N5Avl5rJY7/SEe
rdeL48LsAON8DpDAM9Zg0ykZ+/gsYI/C8b5Ch3QVgU9m50j9q8pVT04EOCYmsFi0
DBnwNBRLDESvm1p6NqKEc7zO9zjABgBvwL+loEVa1JFcp5ECQQD9/sekGTzzvKa5
SSVQOZmbwttPBjD44KRKi6LC7rQahM1PDqmCwPFgMVpRZL6dViBzYyWeWxN08Fuv
p+sIwwLrAkEA+1f3VnSgIduzF9McMfZoNIkkZongcDAzjQ8sIHXwwTklkZcCqn69
qTVPmhyEDA/dJeAK3GhalcSqOFRFEC812QJAXStgQCmh2iaRYdYbAdqfJivMFqjG
vgRpP48JHUhCeJfOV/mg5H2yDP8Nil3SLhSxwqHT4sq10Gd6umx2IrimEQJAFNA1
ACjKNeOOkhN+SzjfajJNHFyghEnJiw3NlqaNmEKWNNcvdlTmecObYuSnnqQVqRRD
cfsGPU661c1MpslyCQJBAPqN0VXRMwfU29a3Ve0TF4Aiu1iq88aIPHsT3GKVURpO
XNatMFINBW8ywN5euu8oYaeeKdrVSMW415a5+XEzEBY=
-----END RSA PRIVATE KEY-----

我從ssl證書文件中提取了公鑰。

下面是我試圖驗證私鑰是否與ssl證書匹配的代碼。

我使用模數[即私鑰獲取模數==公鑰獲取模數]來檢查它們是否匹配..

這似乎只適用於RSAKEYS ..

但我想檢查其他鑰匙..

有沒有其他選擇做同樣的事情。??

  private static boolean verifySignature(File serverCertificateFile, File serverCertificateKey) {
    try {
        byte[] certificateBytes = FileUtils.readFileToByteArray(serverCertificateFile);
        //byte[] keyBytes = FileUtils.readFileToByteArray(serverCertificateKey);
        RandomAccessFile raf = new RandomAccessFile(serverCertificateKey, "r");
        byte[] buf = new byte[(int) raf.length()];
        raf.readFully(buf);
        raf.close();
        PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(buf);
        KeyFactory kf;
        try {
            kf = KeyFactory.getInstance("RSA");

            RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(kspec);


            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
            InputStream in = new ByteArrayInputStream(certificateBytes);
            //Generate Certificate in X509 Format
            X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
            RSAPublicKey publicKey = (RSAPublicKey) cert.getPublicKey();

            in.close();
            return privKey.getModulus() == publicKey.getModulus();

        } catch (NoSuchAlgorithmException ex) {
            logger.log(Level.SEVERE, "Such algorithm is not found", ex);
        }  catch (CertificateException ex) {
            logger.log(Level.SEVERE, "certificate exception", ex);
        } catch (InvalidKeySpecException ex) {
            Logger.getLogger(CertificateConversion.class.getName()).log(Level.SEVERE, null, ex);
        }

    } catch (IOException ex) {
        logger.log(Level.SEVERE, "Signature verification failed.. This could be because the file is in use", ex);
    }
    return false;
}

並且代碼也不起作用..拋出invalidkeyspec異常

使用私鑰對某些內容進行簽名,並使用證書中的公鑰對其進行驗證。 除非他們是一對,否則這將失敗。

那么,成對參數檢查的問題是什么?

  • 如果certificate指定“RSA”類型的公鑰,則:
    1. 從密鑰文件中提取ne
    2. 將這些值與證書中的值進行比較。
  • 如果certificate指定“DSA”類型的公鑰,則:
    1. 從密鑰文件中提取pqgy
    2. 將這些值與證書中的值進行比較。
  • 如果certificate指定類型為“blah-blah”的公鑰,則:
    1. 從密鑰文件中提取相應的值。
    2. 將這些值與證書中的值進行比較。

等等,即每個算法都需要自己正確的處理。 如果密鑰文件格式實際上是自定義的,則不存在通用算法。 但是,您仍可以通過僅指定值索引來略微概括它:

ComparisonScheme = new Dictionary<String, Integer[2][]> {
    { "RSA", {{0, 0}, {1, 1}} },
    { "DSA", {{0, 1}, {1, 2}, {2, 3}, {3, 0}} },
}

當然,這只是一個例子 - 不要認真對待語法和數字。

如果要檢查,如果RSA publicKey和RSA privateKey屬於一起,則可以使用以下代碼:

RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
return rsaPublicKey.getModulus().equals( rsaPrivateKey.getModulus() )
    && BigInteger.valueOf( 2 ).modPow( rsaPublicKey.getPublicExponent()
    .multiply( rsaPrivateKey.getPrivateExponent() ).subtract( BigInteger.ONE ),
    rsaPublicKey.getModulus() ).equals( BigInteger.ONE );

我正在為EC尋找類似的解決方案......


到目前為止,我們已經找到了ECC的方法:但是它有點復雜:

ECPublicKey pk = (ECPublicKey) publicKey;
ECPrivateKey sk = (ECPrivateKey) privateKey;
ECParameterSpec pkSpec = pk.getParams(), skSpec = sk.getParams();
EllipticCurve skCurve = skSpec.getCurve(), pkCurve = pkSpec.getCurve();
ECField skField = skCurve.getField(), pkField = pkCurve.getField();
BigInteger skA = skCurve.getA(), skB = skCurve.getB();
if ( pkSpec != skSpec //
  && ( pkSpec.getCofactor() != skSpec.getCofactor() //
    || ! pkSpec.getOrder().equals( skSpec.getOrder() ) //
    || ! pkSpec.getGenerator().equals( skSpec.getGenerator() ) //
    || pkCurve != skCurve //
    && ( ! pkCurve.getA().equals( skA ) //
      || ! pkCurve.getB().equals( skB ) //
      || skField.getFieldSize() != pkField.getFieldSize() ) ) ) //
  return false;
ECPoint w = pk.getW();
BigInteger x = w.getAffineX(), y = w.getAffineY();
if ( skField instanceof ECFieldFp ) {
  BigInteger skP = ( (ECFieldFp) skField ).getP();
  return pkField instanceof ECFieldFp && skP.equals( ( (ECFieldFp) pkField ).getP() ) //
    && y.pow( 2 ).subtract( x.pow( 3 ) ).subtract( skA.multiply( x ) ).subtract( skB ).mod( skP ).signum() == 0;
}
if ( skField instanceof ECFieldF2m ) {
  int m = ( (ECFieldF2m) skField ).getM();
  BigInteger rp = ( (ECFieldF2m) skField ).getReductionPolynomial();
  if ( ! ( pkField instanceof ECFieldF2m ) || m != ( (ECFieldF2m) skField ).getM() || ! rp.equals( ( (ECFieldF2m) skField ).getReductionPolynomial() ) )
    return false;
  BigInteger x2 = f2mReduce( f2mMultiply( x, x ), rp, m );
  return f2mReduce( f2mSum( f2mMultiply( y, y ), f2mMultiply( x, y ), f2mMultiply( x, x2 ), f2mMultiply( skA, x2 ), skB ), rp, m ).signum() == 0;
}

以下是數學輔助函數:

public static final BigInteger f2mSum( BigInteger ... values )
{
  if ( values.length == 0 )
    return BigInteger.ZERO;
  BigInteger result = values[ 0 ];
  for ( int i = values.length - 1; i > 0; i -- )
    result = result.xor( values[ i ] );
  return result;
}


public static final BigInteger f2mAdd( BigInteger a, BigInteger b )
{
  return a.xor( b );
}


public static final BigInteger f2mSubtract( BigInteger a, BigInteger b )
{
  return a.xor( b );
}


public static final BigInteger f2mMultiply( BigInteger a, BigInteger b )
{
  BigInteger result = BigInteger.ZERO, sparse, full;
  if ( a.bitCount() > b.bitCount() ) {
    sparse = b;
    full = a;
  } else {
    sparse = b;
    full = a;
  }
  for ( int i = sparse.bitLength(); i >= 0; i -- )
    if ( sparse.testBit( i ) )
      result = result.xor( full.shiftLeft( i ) );
  return result;
}


public static final BigInteger f2mReduce( BigInteger input, BigInteger reductionPolynom, int bitLength )
{
  while ( input.bitLength() > bitLength )
    input = input.xor( reductionPolynom.shiftLeft( input.bitLength() - reductionPolynom.bitLength() ) );
  return input;
}

您的代碼很好,只需添加以下內容:

    String file = "qwerty";
    byte[] fileBytes = file.getBytes();
    byte[] digitalSignature = signData(fileBytes, privKey);
    System.out.println("SIGNATURE MADE");
    boolean verified;
    verified = verifySig(fileBytes, publicKey, digitalSignature);
    System.out.println("verified: " + verified) ;

  public static byte[] signData(byte[] data, PrivateKey key) throws Exception {
    Signature signer = Signature.getInstance("SHA256withRSA");
    signer.initSign(key);
    signer.update(data);
    return (signer.sign());
  }

  public static boolean verifySig(byte[] data, PublicKey key, byte[] sig) throws Exception {
    Signature signer = Signature.getInstance("SHA256withRSA");
    signer.initVerify(key);
    signer.update(data);
    return (signer.verify(sig));
  }

我對此有點生疏,但有一點幫助比沒有好嗎?

通常,一旦擁有公鑰/私鑰,您就應該能夠使用密碼使用一個密鑰加密一些少量數據,並查看是否可以使用另一個密鑰成功解密。 這是一種蠻力,可能會影響性能,但可能適合你想要做的事情(我會提供代碼,但我在一個我無法測試它的環境中,我不想發布任何內容如果你感興趣, 使用RSA加密和解密java中的大字符串有使用密碼的代碼片段。

此外,除非標頭已在您的示例私鑰文件中被篡改,否則它不是PKCS8格式。 PKCS8文件不會在標頭中指定算法(例如RSA),因為它們可以使用不同的算法,從而指定編碼本身使用的算法。

另外,如果我沒記錯的話,原生java對PEM的支持很糟糕。 我相信您需要從密鑰文件中刪除PEM標頭,然后base64對其進行解碼,然后才能對其執行任何操作。 或者,如果可能,您可以確保您的密鑰文件是DER編碼的,在這種情況下,密鑰規范應該讀得很好。

如果橢圓曲線鍵匹配,此解決方案在我的情況下可用於初步檢查:

boolean matches(PrivateKey privateKey, PublicKey publicKey) {
    return ((ECKey) privateKey).getParams().equals(((ECKey) publicKey).getParams());
}

另見@ SteffenHeil對更多數學檢查的答案,這些檢查為我提供了相同的結果。

同樣有趣的是,Apple Pay發行的商家支付處理證書與((ECKey) publicKey).getParams() Apple)開發商關系CA-G2“父母”完全相同((ECKey) publicKey).getParams() 因此它們都匹配私鑰,只有使用getSubjectDN() = getIssuerDN()檢查才能解析葉子。

暫無
暫無

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

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