在代码中硬编码 public 键而不是从 public.der 中挑选它

Hard coding public key in code Rather than picking it from public.der

我使用 openssl 创建了 public.derprivate.der。我需要将生成的 public 密钥硬编码到代码中,而不是从 public.der 文件中读取该密钥。当我将文件中的键读入 byte[] 并打印该字节数组时,我得到了 "[B@74a14482" 之类的输出。我可以 运行 通过从文件中读取密钥来编程,但是执行需要时间,所以我想直接将密钥硬编码到程序中。 我有以下功能

public PublicKey readPublicKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, URISyntaxException {
    String str = "[B@74a14482";
    byte[] b = str.getBytes();
    X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(b);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");

    return keyFactory.generatePublic(publicSpec);
}

但它给我的错误是

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: Detect premature EOF

我提到了 to this 和 运行 但我得到了同样的错误。

打印字节数组的代码:

public byte[] readFileBytes(String filename) throws IOException, URISyntaxException {

    return ByteStreams.toByteArray(ResourceLoader.loadFile(filename));
}

public PublicKey readPublicKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, URISyntaxException {
    System.out.println(readFileBytes(filename));
    String str = "[B@74a14482";

    byte[] keyBytes;
    keyBytes = (new BASE64Decoder()).decodeBuffer(str);
    X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");

    return keyFactory.generatePublic(publicSpec);
}

你能帮我解决这个问题吗?我哪里错了。

正如@michalk 所指出的,您打印的是对字节数组应用 toString() 方法的结果。该方法不打印数组内容。

另一个问题是不是所有字节都可以转换为可打印字符。

我建议用 Base64 加注密钥,这将为您提供密钥的可打印版本。然后你可以在使用它之前解码这个字符串。

打印文件内容

byte [] keyBytes = readFileBytes(filename);
String keyString = Base64.getEncoder().encodeToString(key);
System.out.println(keyString);

解码字符串中的密钥

byte[] keyBytes = Base64.getDecoder().decode(keyString);

(而不是 keyBytes = (new BASE64Decoder()).decodeBuffer(str);

byte[]

System.out.println() 只打印 对象的哈希码 而不是内容;欺骗 What's the simplest way to print a Java array? 和许多其他评级较低或封闭的问题。此外,哈希码甚至与 base64 都不相似,因此尝试将其解码为 base64 完全没用。

RSA 密钥编码会大得多。例如,这里是我的测试 RSA 密钥之一,表示为 byte[] 变量的有效初始值设定项:

{48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -79, -123, 63, 50, -126, 49, 97, -27, 110 , 8, 87, 43, 95, -25, -60, 31, -107, -41, -2, 23, -65, -100, -108, -46, 67, -93, -8, 68, 93, -4, 12, -94, -51, -100, -37, 80, -11, 119, -25, 104, -63, 15, -109, 97, 23, -127, 34, 7, -109, -27, 87, -124, 79, 111, 100, -36, 108, 87, -79, 38, -114, 14, -126, -7, -28, 113, 80, 29, 77 , 12, 27, 86, 25, 127, -45, -77, 103, 14, 96, 63, 25, -123, 43, -90, -124, -22, 101, 40, -95, 38, 116, 73, 51, 25, 79, -47, 122, 109, -26, -55, -16, 118, 5, 7, -115, -23, 20, -111, 22, 40, 25, 126 , -60, 118, 35, -118, 26, 67, -106, 3, 88, -99, -18, -109, -94, 49, -47, 115, 120, -51, 12, 38, -73, 13, 109, -11, 111, 109, -128, 54, 64, 76, 50, -42, -45, -17, 46, 83, 77, -106, 115, 97, -21, 33、-52、-114、-68、58、-119、13、124、-1、93、86、62、23、-22、100、-81、11、63、-54、3、-95 , -58, -43, 93, 53, -114, -21, -34, 103, -110, 42, 52, -108, 86, 67, -94, 92, -57, 90, -88, -81, -74, -46, 95, -40, -82, -6, 25, 69, 87, -70, 28, 66, 19, -90, -17, 109, -1, 30, -104, 13, -86, 19, 78, 27, 27, -90, -40, -28, 0, -96, 88, -91, 33, -74, 81, -27, -55, -98, 116, 12, -56, -96, -10, 25, 61, -50, -69, 40, -82, -90, -2, -27, 62, -117, -17, 45, -106, 98, -87, -11, 72, 89, 2, 3, 1, 0, 1}

由于 Java/JVM 初始化数组的方式,尤其是较大的数组,这很可能很慢,您(仅)在评论中说这是您真正关心的问题。 (这与 C 和 C++ 不同,在 C 和 C++ 中,至少静态持续时间初始化的数组通常由编译器处理,并由系统加载程序简单地读取 - 或者经常映射 - 。)根据我读取文件的经验,实际 Java 很快,只要文件是真实的本地文件,但我不知道你的 'ResourceLoader' 在做什么。

像大多数人一样使用 base64 可能会得到更好的结果。 Base64 是由适合在 String 中处理的字符组成的文本,与 DER 中的任意二进制数据不同,并且字符串常量在 Java class 文件中进行了优化,特别是在 j9 up 中,其中只有 ASCII 常量可以在字符串中保留 1 个字节(尽管 base64 解码器可能仍会扩展为 2 个字节)。添加:提交后我看到 Benoit 已经提供了 base64 实现。