asn.1 rsa java,错误:0D0680A8:asn1编码例程:ASN1_CHECK_TLEN:导入RSA公钥时错误的标签...

本文介绍了一种在Android项目中遇到的RSA公钥导入失败的问题,并提供了详细的错误信息及解决方案。通过去除公钥字符串中的BEGIN和END标签并进行Base64解码,成功解决了导入异常。

I've generated a RSA pair of keys (public and private). Now for testing purposes I'm trying to import the public key in String representation into a PublicKey to use it within an Android project, in order to send crypted messages in RSA to a remote server which will afterwards decrypt them using the private key.

public static String encryptDataRSA(final String data) throws IOException {

final byte[] dataToEncrypt = data.getBytes();

byte[] encryptedData = null;

try {

final String keyStr = "-----BEGIN PUBLIC KEY-----\n" +

"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdQudusozLmogBfU2LCO+WcM59\n" +

"ycup9SxMsBNCku23PxrPMO6u//QjtWPz7istE9vkQfa6tQn1Or+SDxeHLMxEesF0\n" +

"xiBEgFUhg7vjOF2SnFQQEADgUyizUIBBn1UgKNA8eP24Ux0P0M2aHMn78HIHsRcu\n" +

"pNGUNW7p51HOVoIPJQIDAQAB\n" +

"-----END PUBLIC KEY-----";

PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyStr.getBytes()));

final Cipher cipher = Cipher.getInstance("RSA");

cipher.init(Cipher.ENCRYPT_MODE, publicKey);

encryptedData = cipher.doFinal(dataToEncrypt);

try {

final String encryptedText = new String(Base64.encode(encryptedData, Base64.DEFAULT), "UTF-8");

return encryptedText.toString();

}

catch (final UnsupportedEncodingException e1) { return null; }

} catch (Exception e) { e.printStackTrace(); }

return "ERROR";

}

The problem is that this is returning the following exception:

03-19 21:14:31.449: W/System.err(2713): java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag

03-19 21:14:31.480: W/System.err(2713): at org.apache.harmony.xnet.provider.jsse.OpenSSLKey.getPublicKey(OpenSSLKey.java:89)

03-19 21:14:31.480: W/System.err(2713): at org.apache.harmony.xnet.provider.jsse.OpenSSLRSAKeyFactory.engineGeneratePublic(OpenSSLRSAKeyFactory.java:47)

03-19 21:14:31.489: W/System.err(2713): at java.security.KeyFactory.generatePublic(KeyFactory.java:171)

03-19 21:14:31.489: W/System.err(2713): at com.mydomain.myproject.SecurityTools.encryptDataRSA(SecurityTools.java:85)

03-19 21:14:31.501: W/System.err(2713): at com.mydomain.myproject.MainActivity.onCreate(MainActivity.java:93)

03-19 21:14:31.501: W/System.err(2713): at android.app.Activity.performCreate(Activity.java:5133)

03-19 21:14:31.509: W/System.err(2713): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)

03-19 21:14:31.521: W/System.err(2713): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)

03-19 21:14:31.521: W/System.err(2713): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)

03-19 21:14:31.529: W/System.err(2713): at android.app.ActivityThread.access$600(ActivityThread.java:141)

03-19 21:14:31.529: W/System.err(2713): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)

03-19 21:14:31.541: W/System.err(2713): at android.os.Handler.dispatchMessage(Handler.java:99)

03-19 21:14:31.541: W/System.err(2713): at android.os.Looper.loop(Looper.java:137)

03-19 21:14:31.561: W/System.err(2713): at android.app.ActivityThread.main(ActivityThread.java:5103)

03-19 21:14:31.571: W/System.err(2713): at java.lang.reflect.Method.invokeNative(Native Method)

03-19 21:14:31.581: W/System.err(2713): at java.lang.reflect.Method.invoke(Method.java:525)

03-19 21:14:31.592: W/System.err(2713): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)

03-19 21:14:31.601: W/System.err(2713): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)

03-19 21:14:31.609: W/System.err(2713): at dalvik.system.NativeStart.main(Native Method)

03-19 21:14:31.621: W/System.err(2713): Caused by: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag

03-19 21:14:31.649: W/System.err(2713): at org.apache.harmony.xnet.provider.jsse.NativeCrypto.d2i_PUBKEY(Native Method)

03-19 21:14:31.649: W/System.err(2713): at org.apache.harmony.xnet.provider.jsse.OpenSSLKey.getPublicKey(OpenSSLKey.java:87)

03-19 21:14:31.663: W/System.err(2713): ... 18 more

The exception points to this line: cipher.init(Cipher.ENCRYPT_MODE, publicKey);

Why is this returning this exception and how to solve it? Thanks.

解决方案

X509EncodedKeySpec expects DER-encoded data, not PEM-encoded. Your code will work fine if you simply discard the "BEGIN" and "END" and base64-decode the public keys contents.

final String key2 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdQudusozLmogBfU2LCO+WcM59"

+ "ycup9SxMsBNCku23PxrPMO6u//QjtWPz7istE9vkQfa6tQn1Or+SDxeHLMxEesF0"

+ "xiBEgFUhg7vjOF2SnFQQEADgUyizUIBBn1UgKNA8eP24Ux0P0M2aHMn78HIHsRcu"

+ "pNGUNW7p51HOVoIPJQIDAQAB";

PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(

new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(key2)));

<think>我们正在处理错误 `error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag`。该错误通常出现在处理证书或密钥,表明 ASN.1 数据结构中的标签(tag)与预期不符。根据引用内容,该错误在Android平台上使用支付宝SDK或处理X.509证书常见。 ### 错误原因分析 1. **证书或密钥格式错误**:输入的数据不是有效的DER或PEM格式,或者数据损坏。引用[3]和[4]指出,在解析X.509证书或公钥,遇到了错误标签(wrong tag),这意味着解析器在期望的位置没有找到预期的ASN.1标签。 2. **版本兼容性问题**:引用[2]提到,在模拟器或手机版本过高,支付宝Demo会发生崩溃并抛出此错误,这可能是因为高版本Android系统对安全证书的校验更严格。 3. **错误编码方式**:引用[4]中,使用`X509EncodedKeySpec`加载公钥,如果传入的字节数组不是有效的X.509编码公钥,就会导致此错误。 ### 解决方案 #### 步骤1:验证证书/密钥的完整性 - 检查证书或密钥文件是否损坏或不完整。可以通过以下命令验证PEM格式的证书: ```bash openssl x509 -in certificate.pem -text -noout ``` 如果证书无效,命令会报错。 #### 步骤2:转换证书格式(如果需要) 如果证书是DER格式(二进制),可以转换为PEM格式: ```bash openssl x509 -inform der -in certificate.cer -out certificate.pem ``` #### 步骤3:代码端修复(Java示例) 在Java代码中加载公钥,确保使用正确的编码方式。引用[4]中,使用`X509EncodedKeySpec`加载公钥,但输入流可能不是有效的X.509公钥。请检查公钥数据是否正确。 示例修复代码: ```java // 正确加载PEM格式的公钥(需去除头尾标记和换行符) public static PublicKey loadPublicKey(String publicKeyPem) throws Exception { // 去除PEM头尾标记和换行符 String base64PublicKey = publicKeyPem .replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replaceAll("\\s", ""); // 去除所有空白字符 byte[] keyBytes = Base64.decode(base64PublicKey, Base64.DEFAULT); X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(spec); } ``` #### 步骤4:处理支付宝SDK的兼容性问题(针对引用[2]) 如果是支付宝SDK在高版本Android上出现此错误,可能是因为SDK版本过旧。解决方案: 1. 更新支付宝SDK到最新版本。 2. 如果问题依旧,尝试在AndroidManifest.xml中设置兼容模式: ```xml <application android:usesCleartextTraffic="true" ...> ``` 因为高版本Android默认禁止明文传输(HTTP),而旧版SDK可能使用HTTP。 #### 步骤5:使用Bouncy Castle库解析 如果系统默认解析器无法处理证书,可以尝试使用Bouncy Castle库: ```java Security.addProvider(new BouncyCastleProvider()); CertificateFactory certFactory = CertificateFactory.getInstance("X.509", "BC"); X509Certificate cert = (X509Certificate) certFactory.generateCertificate(inputStream); ``` ### 完整解决流程 ```mermaid graph TD A[出现错误] --> B{检查证书/密钥完整性} B -->|完整| C[检查格式 PEM/DER] B -->|损坏| D[重新获取证书] C -->|DER格式| E[转换为PEM格式] C -->|PEM格式| F[代码加载逻辑检查] E --> F F --> G{是否使用支付宝SDK} G -->|是| H[更新SDK或设置兼容模式] G -->|否| I[使用Bouncy Castle库解析] H --> J[问题解决] I --> J ``` ### 相关问题 §§相关问题§§ 1. 如何验证X.509证书的合法性? 2. Android高版本为何对证书校验更严格? 3. Bouncy Castle库如何集成到Android项目? 4. 支付宝SDK在高版本Android上还有哪些兼容性问题? 5. ASN.1编码规则是什么? </think>## 错误原因分析 错误 `error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag` 表示 ASN.1 数据结构中的标签值与预期不符。根据引用[1][2][3],该问题常见于以下场景: 1. **密钥/证书编码格式错误** - 使用了错误编码格式(如将 PEM 格式密钥当作 DER 处理) - 证书链中混合了不同标准的证书格式(如 X.509 v1 和 v3) - 引用[3]中显示:Android 系统在解析 OpenSSL 证书遇到标签不匹配 2. **Android 高版本兼容性问题** 引用[2]明确指出:支付宝 SDK 在 Android 高版本设备上会因此崩溃,因为新系统强化了 ASN.1 结构验证 3. **密钥加载方式错误** 引用[4]展示的代码片段 `X509EncodedKeySpec` 表明:直接将字节流转换为密钥规范,未验证数据格式是否符合 $ \text{ASN.1} = \text{SEQUENCE} + \text{OBJECT IDENTIFIER} + \text{BITSTRING} $ 结构[^1]。 --- ## 解决方案 ### 步骤 1:验证密钥/证书格式 ```bash # 证书验证 openssl x509 -in cert.pem -text -noout # 密钥验证(RSA示例) openssl rsa -in key.pem -check ``` - 若输出 `unable to load certificate` 或 `Expecting: TRUSTED CERTIFICATE`,说明格式错误[^3] ### 步骤 2:转换证书格式 解决 PEM/DER 格式混淆问题: ```bash # PEM转DER(证书) openssl x509 -in cert.pem -outform der -out cert.der # DER转PEM(密钥) openssl rsa -inform der -in key.der -out key.pem ``` ### 步骤 3:修复 Android 代码(Java) ```java // 正确加载公钥的方法 public static PublicKey loadPublicKey(InputStream in) throws Exception { byte[] keyBytes = IOUtils.toByteArray(in); // 移除PEM头尾标记 String pem = new String(keyBytes, StandardCharsets.UTF_8); pem = pem.replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replaceAll("\\s", ""); // 移除所有空白符 // Base64解码 byte[] decoded = Base64.getDecoder().decode(pem); // 使用X509EncodedKeySpec验证ASN.1结构 X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded); KeyFactory kf = KeyFactory.getInstance("RSA"); return kf.generatePublic(spec); } ``` ### 步骤 4:支付宝 SDK 兼容性处理 针对引用[2]的高版本 Android 问题: 1. 更新支付宝 SDK 到最新版本 2. 在 `AndroidManifest.xml` 中添加: ```xml <application android:usesCleartextTraffic="true" ...> ``` 3. 使用 Bouncy Castle 提供者: ```java Security.addProvider(new BouncyCastleProvider()); ``` ### 步骤 5:ASN.1 结构验证 通过 ASN.1 解析器检查数据结构: ```bash openssl asn1parse -in key.pem -i ``` 正常 RSA 公钥应显示: ``` 0:d=0 hl=4 l= 266 cons: SEQUENCE 4:d=1 hl=4 l= 257 prim: INTEGER :RSA modulus 265:d=1 hl=2 l= 3 prim: INTEGER :65537 ``` --- ## 完整解决流程 ```mermaid graph TD A[遇到错误] --> B{是否Android高版本?} B -->|是| C[更新支付宝SDK] B -->|否| D[验证证书格式] C --> E[添加usesCleartextTraffic] D --> F{PEM/DER格式?} F -->|PEM| G[检查Base64完整性] F -->|DER| H[转换为PEM验证] G --> I[使用openssl asn1parse解析] H --> I I --> J{标签是否匹配?} J -->|否| K[重新生成密钥] J -->|是| L[修复代码加载逻辑] ``` ### 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值