JAVA中的签名验证和签名长度

Posted

技术标签:

【中文标题】JAVA中的签名验证和签名长度【英文标题】:Signature Verification in JAVA and Signature Length 【发布时间】:2018-09-18 19:30:05 【问题描述】:

我开发了一个java应用程序,它从PEM文件中读取公钥,然后验证签名。我从外部(一家公司)收到了这个签名,它是使用 RSA2048 生成的。但是我收到以下错误消息:

“签名长度不正确:得到 384 但预期为 256。”

在验证之前我必须对这个签名做一些修改吗?

 package read_key_pck;

import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Main 

    //protected final static Logger LOGGER = Logger.getLogger(Main.class);

    public final static String RESOURCES_DIR = "C:\\Users\\KX5710\\eclipse-workspace\\read_key\\src\\read_key_pck\\";

    public static boolean verify(String plainText, String signature, PublicKey publicKey) throws Exception 
        Signature publicSignature = Signature.getInstance("SHA256withRSA");
        publicSignature.initVerify(publicKey);
        publicSignature.update(plainText.getBytes(UTF_8));

        byte[] signatureBytes = Base64.getDecoder().decode(signature);

        return publicSignature.verify(signatureBytes);
    

    public static void main(String[] args) throws Exception 
        Security.addProvider(new BouncyCastleProvider());

        PublicKey pub = null;
        KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
        try 
            /*PrivateKey priv = generatePrivateKey(factory, RESOURCES_DIR
                    + "id_rsa");*/


            pub = generatePublicKey(factory, RESOURCES_DIR
                    + "rsa_2048_pub.pem");

         catch (InvalidKeySpecException e) 
            e.printStackTrace();
        
        String encodedPublicKey = Base64.getEncoder().encodeToString(pub.getEncoded());
        System.out.println("publickey: " + encodedPublicKey);

        boolean isCorrect = verify("         5   5.00   1.80", "12c1d454cde1c3ca07f179fc3c8d1e739b482b0447cd2c60342455a10db15ee8657e73e7f9195f7e33d93db8fc1cda236d41bf2a804be0f860c16ebf952c02e89f254a19daf54b66d1383ebe5aaf049e7c48ecd33a98f771165cb8b7b0323d81508c6260109c8f622655f363bbf638802d92c985e8ab982eebc7167c979cde4755b7afcc880e32118c3e6b72eecbd0ebf680da84a59c8cc523051c3a8ec12595ec6bdc0856b9faf9562919c315e78655c8f35f759899f27d729e56a96ec8bd85fe6221441dd91f9facd5f5eadcb4b7fac08a9ddab29f18d353e6762e0769068077fea7bc94d6df405a86c9e98096e8e50e59ec7263ce6c4e88bb96ab3c663baa", pub);
        System.out.println("Signature verification: " + isCorrect);
    

    private static PublicKey generatePublicKey(KeyFactory factory,
            String filename) throws InvalidKeySpecException,
            FileNotFoundException, IOException 
        PemFile pemFile = new PemFile(filename);
        byte[] content = pemFile.getPemObject().getContent();
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
        return factory.generatePublic(pubKeySpec);
    



package read_key_pck;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

public class PemFile 

    private PemObject pemObject;

    public PemFile(String filename) throws FileNotFoundException, IOException 
        PemReader pemReader = new PemReader(new InputStreamReader(
                new FileInputStream(filename)));
        try 
            this.pemObject = pemReader.readPemObject();
         finally 
            pemReader.close();
        
    

    public PemObject getPemObject() 
        return pemObject;
    

【问题讨论】:

您的签名被编码为 HEX 而不是 BASE64。将byte[] signatureBytes = Base64.getDecoder().decode(signature); 更改为byte[] signatureBytes = DatatypeConverter.parseHexBinary(signature) @pedrofb 谢谢,现在可以了。 @pedrofb 您应该将其发布为答案,而不是评论 - 然后它可以被正确地投票并标记为已接受。 【参考方案1】:

您的签名被编码为 HEX 而不是 BASE64。 改变

byte[] signatureBytes = Base64.getDecoder().decode(signature); 

byte[] signatureBytes = DatatypeConverter.parseHexBinary(signature)

【讨论】:

以上是关于JAVA中的签名验证和签名长度的主要内容,如果未能解决你的问题,请参考以下文章

验证openssl c ++中的签名,该签名由JAVA DSA签名?

当我只有原始签名(R,S)和原始公钥点(Qx,Qy)时,ECDSA如何验证Java中的数据块

java注解怎么验证参数和签名

openssl 摘要和签名验证指令dgst使用详解

签名验证前发件人证书已过期

.NET RSACryptoServiceProvider 中的 PyCrypto 签名消息和验证签名