繁体   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