You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 17与Swift iOS生成的PKCS#1公钥差异及适配问询

更新(摘要)
  • *Swift(iOS)*生成PKCS#1格式的密钥
  • Java 17生成的密钥外观相似,但采用遵循RFC 5280的**SubjectPublicKeyInfo(简称SPKI)**规范,格式略有不同

目标

生成格式一致的PKCS#1格式公钥

通用方案

分别在以下环境生成4096位RSA公钥:

  • Java 17
  • iOS模拟器(iPhone 14)中的Swift

生成的密钥示例可查看附录。

示例代码:生成密钥对(Swift - iOS)

// Keypair attributes
let tag = "my_personal_keystore_keypair_alias".data(using: .utf8)!
let attributes: [String: Any] =
    [kSecAttrKeyType as String:            kSecAttrKeyTypeRSA,
     kSecAttrKeySizeInBits as String:      "4096",
     kSecPrivateKeyAttrs as String:
        [kSecAttrIsPermanent as String:    true,
         kSecAttrApplicationTag as String: tag]
]
var error: Unmanaged<CFError>?

// Generate PrivateKey / Keypair
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
    throw error!.takeRetainedValue() as Error
}

// Extract PublicKey
guard let publicKey = SecKeyCopyPublicKey(privateKey),
      let publicKeyOptional = SecKeyCopyExternalRepresentation(publicKey, nil) else {
    return "PublicKey could not be accessed."
}
let publicKeyData = publicKeyOptional as Data
let base64PublicKey = publicKeyData.base64EncodedString()
print("PublicKey, base64:   ", base64PublicKey)

示例代码:生成密钥对(Java 17)

private static String getPublicKey() {
    KeyPairGenerator generator;
    try {
        generator = KeyPairGenerator.getInstance("RSA");
    } catch (NoSuchAlgorithmException e) {
        throw new EncryptionException(e);
    }
    generator.initialize(4096);
    KeyPair pair = generator.generateKeyPair();
    return Base64.getEncoder().encodeToString(pair.getPublic().getEncoded());
}
目标:在Java 17中解析密钥

与预期的格式一致相反,Java端代码仅能解析自身生成的密钥。

Java 17生成密钥的解析方案

解析Java 17生成的密钥:

public Optional<PublicKey> validateKeyFromJava(String publicKey) {
    try {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance(EncryptionProperties.ALGORITHM);
        EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        return Optional.ofNullable(keyFactory.generatePublic(publicKeySpec));
    } catch (NoSuchAlgorithmException | InvalidKeySpecException | IllegalArgumentException | NullPointerException e) {
        return Optional.empty();
    }
}

问题:解析Swift(iOS)生成的密钥

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:241)
at java.base/java.security.KeyFactory.generatePublic(KeyFactory.java:351)

非预期方案:Swift(iOS)生成密钥的临时解决办法

引入外部依赖:

import org.bouncycastle.asn1.ASN1Sequence;

可实现iOS密钥的解析,之后可正常加密数据。

解析Swift(iOS)生成的密钥:

public Optional<PublicKey> validateKeyFromIOS (String publicKeyANS1) {
    try {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyANS1);

        ASN1Sequence sequence = ASN1Sequence.getInstance(publicKeyBytes);
        ASN1Integer modulus = ASN1Integer.getInstance(sequence.getObjectAt(0));
        ASN1Integer exponent = ASN1Integer.getInstance(sequence.getObjectAt(1));
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus.getPositiveValue(),
                exponent.getPositiveValue());

        KeyFactory factory = KeyFactory.getInstance(EncryptionProperties.ALGORITHM);

        return Optional.ofNullable(factory.generatePublic(keySpec));
    } catch (NoSuchAlgorithmException e) {
        String errorInfo = "iOS-PublicKey - 预期算法: RSA, 实际: " +
                e.getMessage();
        sendToErrorQueue(e, errorInfo);
        return Optional.empty();
    } catch (InvalidKeySpecException | IllegalArgumentException | NullPointerException e) {
        sendToErrorQueue(e, "iOS公钥不符合预期规范。");
        return Optional.empty();
    }
}

但这是一种不同的密钥读取方式,说明两者密钥存在差异。

总结

两个系统生成的密钥均为PKCS#1格式(可通过在线工具验证),但存在细微差异。

待解答问题:
  1. 两者密钥的具体差异是什么?
  2. 主要问题:Swift(iOS)能否生成与Java 17格式一致的公钥?
  3. 次要问题:Java 17能否不依赖BouncyCastle解析Swift(iOS)生成的公钥?
  • 目标:减少代码中针对不同输入路径的分支判断。
附录

可通过在线工具分析所有密钥,提供多组密钥示例以避免偶然情况。

示例密钥 - Swift iOS

第一组:

MIICCgKCAgEAl0HYn9IdRmexAR9dSh3SxmFazWF0RV2TKmtRxGySvCA+aHZ/Dp+8tC0YDWpQzP+tZdlDWNOBj/D7i1z4b+UZk8F9ZEoi+w61kYQz+KjMkRuYrPBFi4A/gsS2qGeFJ4OvLQzGObZ0C+5/E+wunUWyQCVjgjTHKH8yqfVXeWYFKmaSSZblSZJAObE8Ao5J38DMINF1oWG+GdZt8RTLf35ULLEa8zKvFXrfBkDjiQH90WKPwDxWwvFInqZhjpsFxLytiKW+iBLqa4+0P7uwXVodFXa38RW9dk9mEsLvj6764BKtPAaWym9XZfEZNBu0jwlfO07k0augynGps6bsSIyYglDImlTRagdA/e+1AMBlSxEFVO4NpCjEpMT7rNX/LYPeEaJ8fTC3axOM1yEntcwUfSSCDulVPGlWlFbPxt29y1RrGtMmwfbTlbOQf2okMf0mGx9Ytd9HWadIdWh4FqDVWA8MF82PP1YsOW5TA0hkprK1qJwfkaLRKnmpfL5a7gWn4HWzpdDqrezhbc/zTCeHbX5c61mgWsAIWnB3fyXsJHpR62+QtBEznwhDxafVCQyUmsDqbncBxilEnFIn08G+6ox2PQC8GhNdpFVGsSoqpDfctsm51/tUYLpyeIBdzw/3nMLL1J5jL3yWr7ZKgnzNwjpC8l6c6gpsF3NRodeVhp8CAwEAAQ==

第二组:

MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlSbN7rlX6EMCDGuxQm9G6qqXIWshDvI5VaN4QPNCFcFzPjI/FyaHqi43+mxTyKGycT6TNqvanSu67yoIA80tSlFH2LndWv6sPQeHKxNwwFKU98Y/uL3M6hKIVXDwa6kZGM58dfY9qMWEOPXB4AwZtVaxJ4ePHFAR0kEOAHLCPpQxFkNlkg9FlCwlBzZbhHkI5uhCmlGEiLpLaJNJzjn7yo33m65189J6tIh3vopZ2ahFHb/vo6SVSbtS7Y0YlinJwH3MCGLm5+pKBpE64t5lgEhDPYSF7pKpLhEVqC5ETaya3mYTkXPSCiY/9Mo5zddniUGrxAJaY940jY3QNYeFmWPEEdhhIW2tUbuiM3IlHAqk4Du5p/2o1QcSVZdBsHStSGdcWqs00Z+ooxXwrOpMOUnZeb8Jt5dGDyHwjOmPf0N8dDQwz+5pgOoTkxd/z5cTK9tMv/nC+Mbbt8LRsct16M3LYrRAYnA8unX1ZD3eXTJPOSB/fM9Hmf1ObxQro9tatC5RaJjS0Xg5aepUsey62BW9lj4kHCkRPD4w1OmjDWGUCOSEhwy0KwqFyRBppYUMndEbJb3GKEjpekcQYwjERPtH/vEVxaN5gGYaCORancUaNH+d03zAmi0G830QXQvyohyKUkGw5qljEBH5R5Wqu7YLTlUes0rQEx8DpLVclaMCAwEAAQ==

示例密钥 - Java 17

第一组:

MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqwMRLS3hhNuVBQTqRT4714fbl4h3PtrSZQ8Ry1qMCefFOLzmLmLD/VdnFoHj3QiqlZMlajvVuJonprhOy911aNW2Qs2VZ+zoMkLRjah9gqg00dLVtdWa2FXjAX6bh/rSR6jmF1hzfLPs/CqOKyDpX003AUF/WvgHkuAizQjZeskEDKawbExs6RSSFHNycrGwB9hBhAwGvyZpC2+fqPN/93W2NZ8xyb5H6CmM7pCpG+sTcsEEYOZjjq2HV8vYdM9KHi7O+nmY0MJxjLJ5JOv5oLqPXFt4Epezz4v2C3oE3Leu4gIy1r1D2xHuxu0pyQ9F2nI7a+6mGZbRAYDA8Yq2oidqBDC9pKogoHcMYhXj/G0WNEhE9ODuHg+GkiiGc3zysuKwfKu1Z5ZmUtlI1kVFqUEEi81smylTXtkU/oEf7P0OX94XcNTq1N3iO+nuFayAhINlvLUXwyO4JQUsmCyu0bH17XuNUfbnSCmOfGhFSjpyU0PthW9Qtf9yY9MmyZz9c9T2kfxoUxBnNRhVUZ+Kg8oA6kkNJp/ac+AdZzkPZFev91ZKYCbyI+rcakJ4KBQ5YoprDtpHmAQZ5E3/rWcq1Tis0yiomE2+natrzaO4aQbrljOHEgB6arbMkeu7/sZHEvYfK7ilH7tsZfDdU2DVOV0yxNReYwOHAFgFMTNQvBsCAwEAAQ==

第二组:

MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs9ywiZnmv9Ewf+dIsmwV8ZlZKQNg4lbVLpNptb3pftnoukvBjak1rDqb6GcxXtM+UuBgr4Wigi0TI+vItzWv6QlBB8HShA4WImKrOCD3+U1fFdDpwCxQO+oHqTqeNKhRcKcM0e0C/c88hJo8l9G2OCjIANW3O+pGeMirB/XjPdcQ+d37TFGpRs83wPR8gUFQsH8qQMkS7uOtTCZHfcK6UzbvJB3Gf/llcCSfPYKUMY9SXIc5K9hpI0E1v5EdEUvdbhiilZI0esntr5BzeO5AxH/m9fFPH9ekZZyc9nXsHY7tPOJMD+wsTad4D9NBGi9x+lzxZRdxyDLote4ix+aHSqMgcdtOyJ69WFym2Ty1VfCgrmG8fhC/PZBEzk6obK5uJD4mO3owrKgYsmJgZHO3CbVkmv04+EEPpQLippQu8uCl+2KO480EvjSco5ryVH3XEsAGokBLCsZviBtntY/Ia0OLXPmy7WWXigxsVQkgPZ1SyZa3FUp/Zuwtoo0BWDI/9JdUZPfKhbQkcxtnKbCe8QXf51YUgIfKXPTBlmk/Zj931EzXdQCZFMvgK+I5p79DqCsD9yKbiUnfK9tXJ4SzMfuiLd4pqB0UIMVMQEj5SZPYn7eHRZyje4v96FDwtj56NQ/kZPYXKqLoOv5nvMALZngzJ6aFaGjkWZX9RNQLfA8CAwEAAQ==


内容的提问来源于stack exchange,提问作者d.braun1991

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 11:55:20