如何从String加载RSA公钥以在Java中进行签名验证? [英] How to load RSA public key from String for signature verification in Java?

查看:82
本文介绍了如何从String加载RSA公钥以在Java中进行签名验证?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下公共密钥,它以文本形式存储在数据库(PostgresSQL)中.这是一个字符串,在Java中:

I have the following public key, that is stored in the DB (PostgresSQL) as text. It's a String, in java:

-----BEGIN RSA PUBLIC KEY-----     
MIICCgKCAgEA1ht0OqZpP7d/05373OE7pB7yCVGNGzkUEuCneyfOzps6iA03NbvI
1ZL0Jpp/N3AW73lGdhaoa3X3JE4GsI/bsToVLQwTKmIOC4yjTvBctmFEoyhhTfxW
s1UHZKl4XZ/7THbRlKHhRaTKyfDAbikkMAxNT/qutLAPjnN1qOwjb1oRq52NP6FJ
KWTTikz4UeOHroX+Xthn2fJSJDlQ4YMdBbgrZVx5JcHKNuPTKRf5gI8QQKMSA9Q9
QJRE5OGp7b6dG14ZmOUnUxb00Mp20LgcaGPcuWU+oFsbQaF6W4G4bdkSZRJJXhSg
d4Q7mahpar94/gnztJmth0GzqTWUYyZIWNqIFoMwuOgeaiDV43zb3uLsRVpRKYYy
esmzcOy/jTScVLRCD8QRyu9B2wgCkNAVztQOXPCOOa4O1LlVQWaecIs4WPhOqDhi
KTBhyVkpC1TrrBkp+QMqMqWll1OyVb6k/7uV0qE/i6rHJtjo5v9bcIgYzswyx9CD
9PKl2Q0L0Jg7TMG+yLDIrLfGeuSeEc4XYJzN7bJcCeiizzu5iU9dQUkrncOrq9jn
Ub2pM/+A+JqIsoPK3IY/pJKqH4JYpGKhO1iPQF6iXIZT1r3ZgJUSQtzSeyYqhkla
2uR2BsbPbDqebCuXm3lAsY5w+dujijcn96PKwYha1LsK5sACHuJ79AMCAwEAAQ==
-----END RSA PUBLIC KEY-----

抱歉,我不知道该密钥是如何生成的.我被告知要使用此密钥并验证另一个称为对象"的字符串的签名.有人告诉我,我用来验证对象"的算法是SHA256withRSA.

I don't know how this key has been generated, I'm sorry. I have been told to take this key and verify the signature of another string that I'll call "object". I have been told that the algorithm that I have to use to verify "object" is SHA256withRSA.

因此,我编写了以下java方法来读取密钥

So, I have written the following java method to read the key

private PublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
    publicKey = publicKey.replaceAll("\\n", "");
    publicKey = publicKey.replace("-----BEGIN RSA PUBLIC KEY-----", "");
    publicKey = publicKey.replace("-----END RSA PUBLIC KEY-----", "");
    publicKey = publicKey.trim();
    byte[] keyDecoded = Base64.getDecoder().decode(publicKey.getBytes());
    X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(keyDecoded);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PublicKey pubKey = kf.generatePublic(publicSpec);
    return pubKey;
}

关键是我遇到以下异常:

The point is that I get the following exception:

java.security.InvalidKeyException:IOException:错误解析错误,不是序列

java.security.InvalidKeyException: IOException: algid parse error, not a sequence

我已经在stackoverflow中阅读了很多关于我的问题.其他用户编写的代码与我的代码非常相似(有时相同).所以我绝对不明白为什么它对我不起作用.其他开发人员(同事)在php中也做同样的事情,并且效果很好,因此我将放弃错误的公共密钥的假设.也许我不是很清楚这个过程?请问您有什么线索吗?

I have read plenty of qustions as mine in stackoverflow. The code written by other users is pretty similar (sometimes identical) to mine. So I definitely don't get why it doesn't work for me. Other developers (workmates) are doing the same in php and it works great, so I would discard the hypothesis of wrong public key. Maybe didn't I understood the process clearly? Do you have any clue, please?

我还尝试使用BouncyCastle库来解决该问题,如建议的此处,但是我遇到了同样的异常.以下是我编写的代码:

I have also tried to cope with the problem using BouncyCastle library, as suggested here, but I get the same exception. The following is the code I have written:

private static PublicKey getPublicKey(String publicKey)
        throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
    Security.addProvider(new BouncyCastleProvider());
    PemReader pp = new PemReader(new StringReader(publicKey));
    PemObject pem = pp.readPemObject();
    byte[] content = pem.getContent();
    pp.close();

    X509EncodedKeySpec spec = new X509EncodedKeySpec(content);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePublic(spec);
}

推荐答案

您不能使用X509EncodedKeySpec加载该密钥.根据 JavaDoc文档需要以下格式:

You can't load that key using an X509EncodedKeySpec. According to it's JavaDoc documentation it expects the following format:

SubjectPublicKeyInfo ::= SEQUENCE {
   algorithm AlgorithmIdentifier,
   subjectPublicKey BIT STRING }

相反,您的密钥看起来有所不同.我使用的数据从您的文章,它转换为十六进制数据,并张贴到网上的 ASN.1解码器.

Instead your key looks different. I used the data from your post, converted it to hex data and posted it into the online ASN.1 decoder.

输出是这样的:

SEQUENCE (2 elem)
  INTEGER (4096 bit) 873481340827968071893572683200799871431146795599597693981565010037737…
  INTEGER 65537

您可能会发现您的密钥不包含 AlgorithmIdentifier ,因此无法使用 X509EncodedKeySpec 来加载它.

As you may recognize your key does not contain an AlgorithmIdentifier therefore it can not be loaded using X509EncodedKeySpec.

我的建议是使用BouncyCastle库,并使用 PEMParser 类加载此密钥:

My suggestion would be to use the BouncyCastle library and it's PEMParser class for loading this key:

File pemFile = new File("test.pem");
try (PEMParser pp = new PEMParser(new InputStreamReader(new FileInputStream(pemFile)))) {
    SubjectPublicKeyInfo subjPubKeyInfo = (SubjectPublicKeyInfo) pp.readObject();
    RSAKeyParameters rsa = (RSAKeyParameters) PublicKeyFactory.createKey(subjPubKeyInfo);

    RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsa.getModulus(), rsa.getExponent());
    KeyFactory kf = KeyFactory.getInstance("RSA");
    java.security.PublicKey publicKey = kf.generatePublic(rsaSpec);
    System.out.println(publicKey);
}

或者您可以通过openssl手动将密钥转换为PKCS#8格式.

Or you manually convert the key to PKCS#8 format via openssl.

这篇关于如何从String加载RSA公钥以在Java中进行签名验证?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆