Java 服务器的 Swift RSA 加密公钥失败

标签 swift rsa java-security

我正在尝试使用 Security 框架从 RSA Private key 创建 public base64 key。这是片段。

let tag = "com.example.keys.mykey"
public extension SecKey {
    static func generateBase64Encoded2048BitRSAKey() throws -> (private: String, public: String) {
        let type = kSecAttrKeyTypeRSA
        let attributes: [String: Any] =
            [kSecAttrKeyType as String: type,
             kSecAttrKeySizeInBits as String: 2048
        ]

        var error: Unmanaged<CFError>?
        guard let key = SecKeyCreateRandomKey(attributes as CFDictionary, &error),
            let data = SecKeyCopyExternalRepresentation(key, &error) as Data?,
            let publicKey = SecKeyCopyPublicKey(key),
            let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
                throw error!.takeRetainedValue() as Error
        }
        return (private: data.base64EncodedString(), public: publicKeyData.base64EncodedString())
    }
}

do {
    let (pvtKey, pubKey) = try SecKey.generateBase64Encoded2048BitRSAKey()
    print(pubKey)
} catch let error {
    print(error)
}

这是输出

MIIBCgKCAQEA1ZafTYboquQbCTZMEb1IqHKIr8wiDjdn6e0toRajZCQo9W5zuTlEuctrjJJQ08HcOuK3BPFRaFTUP1RBFvnba/T2S1Mc6WVX81b0DmKS8aPJ83TvvQlH3bZjVqFzndXJHJatcXRkZKlbidNQYxV9OYFCRLwgR5PBoJ1P5tp8f8735vIADOBL/93nFywODSjAWLXcyG5tUyRlRGX7eDodL7jqVOFxVMB7K9UOJehPuJQiheykyPSbBSLE6raZbpCHlranTLdihWYFs2tYbxzNrVbXzgKIxDDjrhDLVFvo3beudKQcLQkSO+m2LJIDT91zAnxVQ075AIn80ZHh5kdyQQIDAQAB

但是这个公钥没有被我们的 Java 服务器接受。它正在抛出相同的异常。

这是java代码片段

public static void main(String[] args) {
        String pubKey = "MIIBCgKCAQEA1ZafTYboquQbCTZMEb1IqHKIr8wiDjdn6e0toRajZCQo9W5zuTlEuctrjJJQ08HcOuK3BPFRaFTUP1RBFvnba/T2S1Mc6WVX81b0DmKS8aPJ83TvvQlH3bZjVqFzndXJHJatcXRkZKlbidNQYxV9OYFCRLwgR5PBoJ1P5tp8f8735vIADOBL/93nFywODSjAWLXcyG5tUyRlRGX7eDodL7jqVOFxVMB7K9UOJehPuJQiheykyPSbBSLE6raZbpCHlranTLdihWYFs2tYbxzNrVbXzgKIxDDjrhDLVFvo3beudKQcLQkSO+m2LJIDT91zAnxVQ075AIn80ZHh5kdyQQIDAQAB";
        PublicKey key = getPublic(pubKey);
    }

    public static PublicKey getPublic(String key)  {
        PublicKey pbKey = null; 
        try {
            byte[] keyBytes = Base64.getDecoder().decode(key);
            System.out.println(keyBytes.length);
            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
            KeyFactory factory = KeyFactory.getInstance("RSA");
            pbKey = factory.generatePublic(spec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return pbKey;
    }

这里是异常(exception)

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
    at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
    at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
    at Main.getPublic(Main.java:40)
    at Main.main(Main.java:28)

但在线 PEM 解析器网站 - https://8gwifi.org/PemParserFunctions.jsp正在接受这个公钥,它在后台使用 bouncycaSTLe 库来验证这个 base64 编码的公钥。

enter image description here

最佳答案

抛出异常是因为在 iOS 上生成的 RSA 公钥的 ASN.1 DER 编码用 PKCS#1 定义的 RSAPublicKey 类型表示,而 Java(以及许多其他语言和工具)期望 DER 编码为由 X.509 定义的 SubjectPublicKeyInfo 类型表示。这个问题当然有两个方面可以解决。如果您选择在 iOS 端转换 RSA 公钥的 DER 编码,您可以使用 this project我最近在 GitHub 上发布了。您可能感兴趣的结构是 RSAPublicKeyExporter ,它使用 SimpleASN1Writer用于转换 DER 编码。下面的代码片段展示了如何使用它:

import RSAPublicKeyExporter

let publicKeyData = ... // Get external representation of RSA public key some how

let x509EncodedKeyData = RSAPublicKeyExporter().toSubjectPublicKeyInfo(publicKeyData)

我发布的答案here包含一些可能有用的信息,以防从钥匙串(keychain)中获取导出的 key 。

关于Java 服务器的 Swift RSA 加密公钥失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56630848/

相关文章:

ios - 在 iOS 中仅使用模数和指数使用 RSA 加密字符串

java - 防止 Java 应用程序执行恶意 Activity

ios - Swift sortinplace 二元运算符 > 不能应用于两个 nsnumber 操作数

ios - FBSDKShareContent 分享本 map 片

Golang : Convert byte array to big. Int

json - 从 Golang 中的模数和指数创建公钥

java - @RunAs javax 安全注解有什么用?

java - 使用带有非 ASCII 密码的 PKCS#12 证书

ios - 如何使用自定义操作删除部分中的单元格?

ios - 在启动应用程序时从 Google Maps IOS 获取当前位置