从文件中读取 public 键

Read public key from file

我正在尝试用我的 java 程序验证一个文件。我不知道我做错了什么,我找到的所有解决方案都不起作用。 这是我的代码:

public boolean pruefeSignatur(File file, File signatur, File publicKey) {
    boolean verifies = false;
    try {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        // encode public key bytes
        FileInputStream keyfis = new FileInputStream(publicKey);
        byte [] encKey = new byte[keyfis.available()];
        keyfis.read(encKey);
        keyfis.close();
        // key specification
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
        // conversion
        KeyFactory keyFactory = KeyFactory.getInstance(pubKeySpec.getFormat());
        // generate publicKey
        PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
        // input signature bytes
        FileInputStream sigfis = new FileInputStream(signatur);
        byte[] sigToVerify = new byte[sigfis.available()];
        sigfis.read(sigToVerify);
        sigfis.close();
        // initialize the signature
        Signature sig = Signature.getInstance("RSA");
        sig.initVerify(pubKey);
        // supply signature object with the data to be verified
        FileInputStream datafis = new FileInputStream(file);
        BufferedInputStream bufin = new BufferedInputStream(datafis);
        byte[] buffer = new byte[1024];
        int len;
        while(bufin.available() != 0) {
            len = bufin.read(buffer);
            sig.update(buffer, 0, len);
        }
        bufin.close();
        //verify signature
        verifies = sig.verify(sigToVerify);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return verifies;
}

使用这段代码我得到了异常: java.security.spec.InvalidKeySpecException: java.lang.ClassCastException: org.bouncycastle.asn1.DERUnknownTag 无法转换为 org.bouncycastle.asn1.ASN1Object

当我使用 Base64 时,例如:

        Base64 decoder = new Base64();
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(decoder.decode(encKey));

我得到异常: java.security.spec.InvalidKeySpecException:java.io.IOException:意外的内容结束标记

我找到的另一个解决方案是将其更改为:

        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
        // conversion
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

但后来我得到了例外: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: 密钥格式无效

我用 Gpg4win 和 Kleopatra 制作了我的密钥。

编辑: 现在我没有得到错误,但函数总是 returns false。所以我不确定是否一切正常。

public boolean pruefeSignatur(File file, File signaturFile, File publicKeyFile) throws IOException {
    boolean verifies = false;
    FileInputStream keyfis = null;
    DataInputStream keydis = null;
    FileInputStream sigfis = null;
    DataInputStream sigdis = null;
    FileInputStream datafis = null;
    DataInputStream datadis = null;
    try {
        // add provider
        Security.addProvider(new BouncyCastleProvider());

        // encode public key bytes
        keyfis = new FileInputStream(publicKeyFile);
        keydis = new DataInputStream(keyfis);
        byte[] keyBytes = new byte[(int) publicKeyFile.length()];
        keydis.readFully(keyBytes);
        keyfis.close();
        keydis.close();

        // key specification
        String modulusBase64 = new String(keyBytes);
        Base64 b64 = new Base64();
        String exponentBase64 = "65337"; //festgelegte Zahl http://crypto.stackexchange.com/questions/3110/impacts-of-not-using-rsa-exponent-of-65537
        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(1, b64.decode(modulusBase64)), new BigInteger(1, b64.decode(exponentBase64)));

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

        // generate publicKey
        PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);

        // read signature
        sigfis = new FileInputStream(signaturFile);
        sigdis = new DataInputStream(sigfis);
        byte[] sigBytes = new byte[(int) signaturFile.length()];
        sigdis.readFully(sigBytes);
        sigfis.close();
        sigdis.close();

        // initialize the signature
        Signature sig = Signature.getInstance("RSA");
        sig.initVerify(publicKey);

        // supply signature object with the data to be verified
        datafis = new FileInputStream(file);
        datadis = new DataInputStream(datafis);
        byte[] dataBytes = new byte[(int) file.length()];
        datadis.readFully(dataBytes);
        /*
        int len;
        while(datadis.available() != 0) {
            len = datadis.read(dataBytes);
            sig.update(dataBytes, 0, len);
        }
        */
        datadis.close();
        datafis.close();
        sig.update(dataBytes);

        //verify signature
        verifies = sig.verify(sigBytes);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (keyfis != null) {
            keyfis.close();
        }
        if (keydis != null) {
            keydis.close();
        }
        if (sigfis != null) {
            sigfis.close();
        }
        if (sigdis != null) {
            sigdis.close();
        }
        if (datafis != null) {
            datafis.close();
        }
        if (datadis != null) {
            datadis.close();
        }
    }
    return verifies;
}

终于有了解决办法:

    InputStream inSig = PGPUtil.getDecoderStream(new FileInputStream(signaturFile));
    //ArmoredInputStream inSig = new ArmoredInputStream(new FileInputStream(signaturFile));
    JcaPGPObjectFactory objFactory = new JcaPGPObjectFactory(inSig);
    PGPSignatureList signatureList = (PGPSignatureList) objFactory.nextObject();
    PGPSignature signature = signatureList.get(0);

    InputStream keyIn = PGPUtil.getDecoderStream(new FileInputStream(publicKeyFile));
    //ArmoredInputStream keyIn = new ArmoredInputStream(new FileInputStream(publicKeyFile));
    JcaPGPPublicKeyRingCollection pgpRing = new JcaPGPPublicKeyRingCollection(keyIn);
    PGPPublicKey publicKey = pgpRing.getPublicKey(signature.getKeyID());

    byte[] bytePublicKeyFingerprint = publicKey.getFingerprint();
    char[] publicKeyFingerprintHexArray = org.apache.commons.codec.binary.Hex.encodeHex(bytePublicKeyFingerprint);
    String publicKeyFingerprintHex = new String(publicKeyFingerprintHexArray);

    signature.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey);

    FileInputStream in = new FileInputStream(file);
    byte[] byteData = new byte[(int) file.length()];
    in.read(byteData);
    in.close();
    signature.update(byteData);

    if (signature.verify() && publicKeyFingerprintHex.equals(fingerprint)) {
        return true;
    } else {
        return false;
    }