如何从未格式化的String获取公共RSA密钥 [英] How to get public RSA key from unformatted String

查看:143
本文介绍了如何从未格式化的String获取公共RSA密钥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在属性文件中有一个未格式化的公钥,这意味着它只包含公钥hexa值:

I have an unformatted public key in a properties file, meaning it only contains the public key hexa value:

K_PUB_CCE =  3082010902820100A515281FAC9ABAA8E966DC1B6EC0F1C431674B4E7BCB718955A34211D5CC6BA53F2C93F67C030A970D4E41341949E6BC3F9336287EEA21702FE663C83D4BAFEE2AAA2EEE7A6AFDC423A159D420E42ABDE2792080249C5D6E25367F804333665CAFB79FD5A59D70B9F69159F4EDAD2DA4B434F41D0EC5217808E7D91FF547C83774E4BDE813302E16377156E52CAF02D1E68371D536AA0E7E32DE484FF4863538DCBC69E8D3E3C1F3CECEA9861DA5516A06D3208F6363B86CF66641BE18C4F41ABD7F1B5CDC9BD964914515DDC58F32F49437BD7E89431C8F484BBCEBA86A5FFF74E01D12E6D1D7EBBF6E5DCD7A9134BF27185F4BD347B23007FF366C0009E14F0203010001

如你所见,它的长度为538六分之一。我想要实现的是获得具有此值的 java.security.PublicKey

As you can see, it's 538 hexas long. What I wanna achieve is to obtain a java.security.PublicKey with this value.

但是当使用此方法时:

private PublicKey createPublicKey(String stringPublicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    byte[] bytesKey= Hex.decodeHex(stringPublicKey.toCharArray());
    X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(bytesKey);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return  keyFactory.generatePublic(encodedKeySpec);
}

我收到以下异常:

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

我做错了什么?我应该使用其他任何关键规范类吗?

What am I doing wrong? Is there any other key spec class I should be using?

推荐答案

将公钥存储为base64字符串相当麻烦然后将其转换回来(因为根据平台格式可能会有所不同)。使用KeyStore文件会容易得多。

It is rather bothersome to store the public key as a base64 String and then convert it back (since also depending on the platform the format might vary). Using a KeyStore file would be much easier.

如果这不是你的选择,还有另外一种方法。您需要输入您的密钥(模数)和使用的指数。指数通常是65537,但也有方法可以找到它(参见参考资料)。这对我有用:

In case this is not an option for you, there is another way. You need to input your key (modulus) and the used exponent. The exponent is usually 65537, but there are also ways to find that out for sure (see references). This works for me:

public static void main(String[] args) {
    try{
        // example key generated via: $ openssl genrsa -out tmp-key.pem 2048
        // modulus and exponent extracted via: $ openssl rsa -text -in tmp-key.pem
        // (modulus 514 hex long)
        String pubModulus = "00e45679a14c6cbd4646bbe90b3c820eb19fe8366822ce2e4beed9d158b9e8863bdc4e3f0fbad31144ef193493dff8619a5aaa7504541c5d97c20cd29c87435eb2e4fbbab8e3b02d82353016c91e971e8d497e1699eeb77a833833617369333c4d0d93cd6f1a9e6090fafd4cbf00b1e0fc6478003ed6e762fb921446c84f0f281117e692a5f76e4b75cbb1252436b3268893195d25344cc3e5d5a52560243d62e5ce8a7bd72a89fce5fbf009435901e274c3cca5eab0f2b2057683ed6e3ed851723adbabb4028a7900ddc46d8c894097c07ab071f6af8fc1c520681e0abd7685f4851d360a7c6d425373da806d356a517ae764093e6999d2cc9305f46a7e1744ed";
        String pubExp = "65537"; // most common exponent is 65537 which encodes to AQAB

        PublicKey key = createPublicKey(pubModulus, pubExp);
        byte[] data = encrypt("Secret Message", key);
        System.out.println(""+data.length); // prints "256" in this example code
    } catch(Exception e) {
        e.printStackTrace();
    }
}

public static PublicKey createPublicKey(String stringPublicKey, String exponentString) throws NoSuchAlgorithmException, InvalidKeySpecException {
    try{
        // for key modulus and exponent value as base64 encoded string from key file
        //BigInteger keyInt = new BigInteger(Base64.getDecoder().decode(stringPublicKey.getBytes("UTF-8")));
        //BigInteger exponentInt = new BigInteger(Base64.getDecoder().decode(exponentString.getBytes("UTF-8")));

        // for key modulus and exponent values as hex and decimal string respectively
        BigInteger keyInt = new BigInteger(stringPublicKey,16); // hex base
        BigInteger exponentInt = new BigInteger(exponentString,10); // decimal base

        RSAPublicKeySpec keySpeck = new RSAPublicKeySpec(keyInt, exponentInt);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return  keyFactory.generatePublic(keySpeck);
    } catch(Exception e) {
        e.printStackTrace();
    }

    return null;
}

public static byte[] encrypt(String message, PublicKey key) {
    try{
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] data = cipher.doFinal(message.getBytes());
        return data;
    } catch(Exception e) {
        e.printStackTrace();
    }

    return new byte[1];
}

修改:

对不起,我刚看到你使用的是十六进制字符串。原始RSA格式应该是一些base64编码值。由于您已经具有十六进制值,因此模数的BigInteger创建应该不同(请参阅源代码编辑)。
同样如下面的注释中所述,Hex字符串或Base64格式不会出现平台问题。这里唯一需要注意的是,在使用getBytes()从String编译到Base64时指定一种格式(例如UTF-8)。如果未指定格式,则将使用平台默认值。

I am sorry, I just saw that you use a Hex string. The original RSA format should be some base64 encoded value. Since you already have the hex value, the BigInteger creation for the modulus should be different (please see source code edit). Also as mentioned in the comments below, the platform issue does not arise for the Hex string or the Base64 format. The only thing to be aware of here, is to specify a format (such as UTF-8) when encoding from String to Base64 with getBytes(). If no format is specified, the platform default will be used.

参考文献:

RSA指数65537

将RSA十六进制字符串转换为PublicKey

如何找出你的指数

关于十六进制密钥长度/格式

将字符串编码到Base64

这篇关于如何从未格式化的String获取公共RSA密钥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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