首页 > 解决方案 > 生成的数字签名 Java 不会在 openssl 中验证

问题描述

我正在用 Java 签署一个二进制文件。我能够在 Java 代码中签名和验证,但是在 openssl 中使用生成的签名时,它无法验证相同的二进制文件。步骤是:加载数据 -> 创建 SHA256 哈希 -> 签名哈希

这应该等同于在 openssl 中执行此操作: openssl dgst -sha256 -sign private.key -binary target.bin > signature.bin verify: openssl dgst -sha256 -verify public.key -signature signature.bin

我验证了 sha256 与从 openssl 生成的匹配。

public class Main {

    public static void main(final String[] args) {
        Signature signer;
        KeyStore ks;
        byte[] signature;
        PrivateKey privateKey;
        PublicKey publicKey;
        String alias = "ctest3";
        String sigfile = "c:\\temp\\signature";
        String datafile = "c:\\temp\\data.bin";

        try {
            ks = KeyStore.getInstance("ncipher.sworld", "nCipherKM");
            FileInputStream in = new FileInputStream("C:\\private\\ctest3.ncsw");
            ks.load(in, null);
        } catch (KeyStoreException |
                NoSuchAlgorithmException |
                CertificateException |
                IOException |
                NoSuchProviderException e) {
            System.err.println(e.getMessage());
            return;
        }

        try {
            privateKey = (PrivateKey) ks.getKey(alias, null);
            Certificate cert = ks.getCertificate(alias);
            publicKey = cert.getPublicKey();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return;
        }

        byte[] payload;
        try {
            payload = Files.readAllBytes(Paths.get(datafile));
        } catch (IOException e) {
            System.out.println(e.getMessage());
            return;
        }

        byte[] spayload = sha256(payload, false);
        if (spayload == null) {
            return;
        }

        try {
            signer = Signature.getInstance("SHA256withECDSA");
            signer.initSign(privateKey);
            signer.update(spayload);
            signature = signer.sign();
        } catch (NoSuchAlgorithmException | SecurityException | SignatureException | InvalidKeyException e) {
            System.out.println(e.getMessage());
            return;
        }

        writeBytesToFile(signature, sigfile);
        KeyPair kp = new KeyPair(publicKey, privateKey);

        if (Verify(datafile, sigfile, kp)) {
            System.out.println("success");
        }
    }

    private static byte[] sha256(byte[] data) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("SHA-256");
            byte[] mDigest = digest.digest(data);
            return mDigest;
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    private static boolean Verify(String filename, String signaturePath, KeyPair kp) {
        Signature verify;
        byte[] dataRaw;
        byte[] signature;
        byte[] data;

        try {
            dataRaw = Files.readAllBytes(Paths.get(filename));
            signature = Files.readAllBytes(Paths.get(signaturePath));
        } catch (IOException e) {
            System.out.println(e.getMessage());
            return false;
        }

        data = sha256(dataRaw, false);
        if (data == null)
            return false;

        try {
            verify = Signature.getInstance("SHA256withECDSA");
            PublicKey pub = kp.getPublic();
            verify.initVerify(pub);
            verify.update(data);
            if (verify.verify(signature))
                return true;
        } catch (NoSuchAlgorithmException | SecurityException | SignatureException | InvalidKeyException e) {
            System.out.println(e.getMessage());
            return false;
        }

        return false;
    }

    private static void writeBytesToFile(byte[] bFile, String fileDest) {
        try (FileOutputStream fileOuputStream = new FileOutputStream(fileDest)) {
            fileOuputStream.write(bFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

标签: javaopenssl

解决方案


结果表明,当使用 SHA256withECDSA 密钥启动 Signature 对象时,它本身将在 sign() 调用期间生成 SHA256 哈希。在上面的代码中删除对“sha256()”的调用将使用 OpenSSL 进行验证。


推荐阅读