将 Apple APNs 身份验证密钥加载到 Java PrivateKey

sce*_*tix 3 java encryption apple-push-notifications

问题

我在将APN 的身份验证密钥加载到Java 时遇到了困难。我的理解是 Java 可以读取 PKCS8 编码的私钥,但我得到了一个例外。

我使用 Bouncy Castle (bcprov-jdk15on-1.55) 时遇到的异常

org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException: unable to process key spec: java.io.IOException: algorithm identifier 1.2.840.10045.2.1 in key not recognised
    at org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.engineGeneratePrivate(Unknown Source)
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:366)
Caused by: java.io.IOException: algorithm identifier 1.2.840.10045.2.1 in key not recognised
    at org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.generatePrivate(Unknown Source)
    ... 29 more
Run Code Online (Sandbox Code Playgroud)

我使用 Java 时遇到的异常 (jdk1.8.0_74)

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: Invalid RSA private key
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
Caused by: java.security.InvalidKeyException: Invalid RSA private key
    at sun.security.rsa.RSAPrivateCrtKeyImpl.parseKeyBits(RSAPrivateCrtKeyImpl.java:206)
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:342)
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:356)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
    at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:316)
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:213)
    ... 28 more
Caused by: java.io.IOException: Version must be 0
    at sun.security.rsa.RSAPrivateCrtKeyImpl.parseKeyBits(RSAPrivateCrtKeyImpl.java:192)
    ... 34 more
Run Code Online (Sandbox Code Playgroud)

执行

我曾尝试同时使用 Java 和 bouncycastle 提供程序:

byte[] pkcs8EncodedKey = Base64.getDecoder().decode(APNS_PRIVATE_KEY);
KeyFactory factory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = factory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey));
Run Code Online (Sandbox Code Playgroud)

我创建了一个示例项目:http : //tutorialpoint.com

这是测试键

org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException: unable to process key spec: java.io.IOException: algorithm identifier 1.2.840.10045.2.1 in key not recognised
    at org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.engineGeneratePrivate(Unknown Source)
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:366)
Caused by: java.io.IOException: algorithm identifier 1.2.840.10045.2.1 in key not recognised
    at org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.generatePrivate(Unknown Source)
    ... 29 more
Run Code Online (Sandbox Code Playgroud)

sce*_*tix 12

解决方案

基本上苹果不使用RSA算法,而是使用ECC(椭圆曲线加密),所以我EC在加载私钥时必须使用算法。

http://rahulatjava.blogspot.si/2014/02/elliptical-curve-cryptography-in-java.html

工作版本

byte[] pkcs8EncodedKey = Base64.getDecoder().decode(APNS_PRIVATE_KEY);
KeyFactory factory = KeyFactory.getInstance("EC");
PrivateKey privateKey = factory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey));
Run Code Online (Sandbox Code Playgroud)