RSA ERROR

这周用了三天的时间学WebService,第一天在网上找资料认识WebService,第二天早上的时候自己发布了WebService,学习了注解,并成功的访问到了发布的WSDL。余下的一天半左右用在了学习SRA,第一次接触SRA是在大三上学期信息安全的课上,当时也实现了SRA算法并且印象中没有遇到什么bug,这次遇到了一些,记录一下。

1. IOException: Detect premature EOF

1.1 问题背景
在文档中直接复制一对秘钥(公钥和私钥),在用其加密和解密的时候出现了java.security.InvalidKeyException: IOException: Detect premature EOF错误。
公钥和私钥

Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: Detect premature EOF
	at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:188)
	at java.security.KeyFactory.generatePublic(KeyFactory.java:304)
	at SINO.encrypt.ras.RsaSignatureByte.getEncryptCipherByPublicKey(RsaSignatureByte.java:164)
	at SINO.encrypt.ras.RsaSignatureString.encryptByPublicKey(RsaSignatureString.java:149)
	at SINO.TestXyjkpt.main(TestXyjkpt.java:24)
Caused by: java.security.InvalidKeyException: IOException: Detect premature EOF
	at sun.security.x509.X509Key.decode(X509Key.java:380)
	at sun.security.x509.X509Key.decode(X509Key.java:386)
	at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:66)
	at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:281)
	at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:184)
	... 4 more

1.2 问题分析:
Detect premature EOF(End Of File)检测到更早的文件结尾,私钥不正确。
自己写了一个生成秘钥对的代码,发现私钥的长度不正确,文档中的私钥是错误的,应该是私钥长度过长,在编辑文档的时只截取了部分私钥。
密钥对
1.3 解决方法:
更改秘钥。

2. IOException: algid parse error, not a sequence

2.1 问题背景
现有两对秘钥,用于Service和ServiceTest之间进行通信,我在两个文件中分别写了

	static String publicKeyA;
	static String privateKeyA;
 
	static {
        try {
            Map<String, Object> keyMap = RsaUtil.genKeyPair();
            publicKeyA = RsaUtil.getPublicKey(keyMap);
            privateKeyA = RsaUtil.getPrivateKey(keyMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
	at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:188)
	at java.security.KeyFactory.generatePublic(KeyFactory.java:304)
	at SINO.encrypt.ras.RsaUtil.encryptByPublicKey(RsaUtil.java:229)
	at SINO.ServiceTest.main(ServiceTest.java:61)
Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
	at sun.security.x509.X509Key.decode(X509Key.java:380)
	at sun.security.x509.X509Key.decode(X509Key.java:386)
	at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:66)
	at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:281)
	at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:184)
	... 3 more

来生成秘钥,Service在用其私钥进行解密的时候出现该错误信息。
2.2 错误分析(??)
错误含义:非序列,类型转换错误,一般出现这个情况的原因是秘钥不是pks8 格式。
2.3 解决方法
直接给定秘钥,不生成。
解决方法

在Stack Overflow上找到的另一种答案,在获取私钥之前调用

java.security.Security.addProvider(
         new org.bouncycastle.jce.provider.BouncyCastleProvider()
);

3.Data must start with zero

3.1 问题背景
加密解密返回的都是byte[],直接解密是没有问题,在ServiceTest中用toString()将其变成字符串进行参数传递,在Service中用getBytes()得到byte[]进行加密解密操作,出现Data must start with zero.
错误示例:

            String string = RsaUtil.encryptByPublicKey(info, Service.publicKeyA).toString();
            System.out.println("加密后:" + string);
            byte[] date = string.getBytes();
	    byte[] date_decryption = RsaUtil.decryptByPrivateKey(date,Service.privateKeyA);
	    System.out.println("解密后:" + new String(date_decryption)); 

错误

javax.crypto.BadPaddingException: Data must start with zero
	at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:308)
	at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:255)
	at com.sun.crypto.provider.RSACipher.a(DashoA13*..)
	at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)
	at javax.crypto.Cipher.doFinal(DashoA13*..)
	at SINO.encrypt.ras.RsaUtil.decryptByPrivateKey(RsaUtil.java:164)
	at SINO.Service.getPhoneInfo(Service.java:83)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.sun.xml.internal.ws.api.server.InstanceResolver$1.invoke(InstanceResolver.java:235)
	at com.sun.xml.internal.ws.server.InvokerTube$2.invoke(InvokerTube.java:135)
	at com.sun.xml.internal.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:246)
	at com.sun.xml.internal.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:82)
	at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:587)
	at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:546)
	at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:531)
	at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:428)
	at com.sun.xml.internal.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:232)
	at com.sun.xml.internal.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:460)
	at com.sun.xml.internal.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:233)
	at com.sun.xml.internal.ws.transport.http.server.WSHttpHandler.handleExchange(WSHttpHandler.java:95)
	at com.sun.xml.internal.ws.transport.http.server.WSHttpHandler.handle(WSHttpHandler.java:80)
	at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:65)
	at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:65)
	at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:68)
	at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:557)
	at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:65)
	at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:529)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)

3.2 问题分析
由于byte值可能是一位到三位,无法知道某一个byte是在哪里结束。因此解析时出错。
3.3 解决方法
要在加密后产生的byte数组转成string时要在各byte之间加个标识符,然后再根据空格分隔转换回byte数组。
代码:

//字节数组转字符串
public static String bytesToString(byte[]  info) {
	     String result = "";
	     for (Byte bytes : info) {
	         result += bytes.toString() + " ";
	     }
	     return result;
	}
//字符串转字节数组
public static byte[] stringToByte(String info) {
	String[] strArr = info.split(" ");
	 int len = strArr.length;		    
	 // 转回bytes
	 byte[]  temp= new byte[len];
	 for (int i = 0; i < len; i++) {
	      temp[i] = Byte.parseByte(strArr[i]);
	 }
	 return temp;
}

结果

在 OpenSSL 证书验证过程中出现 `RSA` 错误,通常与证书链的完整性、密钥类型或签名算法的兼容性有关。以下是对这一问题的详细分析及解决建议: 1. **RSA 密钥长度不足或算法不兼容** 如果证书使用了较短的 RSA 密钥(如 1024 位),某些现代系统或库可能拒绝使用以保证安全性。OpenSSL 在验证证书时会根据安全策略判断是否接受该证书。可以通过检查证书使用的密钥长度和签名算法来确认是否符合当前系统的安全策略。 ```bash openssl x509 -in certificate.pem -text -noout ``` 在输出中查找 `Public-Key` 和 `Signature Algorithm` 字段,确保密钥长度至少为 2048 位,并使用 SHA-256 或更高级别的哈希算法进行签名[^2]。 2. **证书链不完整** 当证书链中缺少中间证书时,OpenSSL 无法构建完整的信任链,从而导致验证失败。可以通过以下命令检查证书链是否完整: ```bash openssl verify -CAfile /path/to/trusted-certs.pem certificate.pem ``` 其中 `/path/to/trusted-certs.pem` 应包含根证书和所有中间证书。如果验证失败,需将缺失的中间证书添加到信任库中[^2]。 3. **OpenSSL 配置问题** 某些 OpenSSL 配置(如 `openssl.cnf`)可能限制了允许使用的算法或密钥类型。可以尝试更新 OpenSSL 配置文件,确保允许使用所需的 RSA 密钥长度和签名算法。 4. **证书过期或时间设置错误** 如果证书已过期或系统时间设置不正确,OpenSSL 会拒绝该证书。可以通过以下命令检查证书的有效期: ```bash openssl x509 -in certificate.pem -noout -dates ``` 确保当前系统时间处于 `notBefore` 和 `notAfter` 指定的时间范围内[^2]。 5. **证书格式或编码问题** 证书文件可能未以正确的格式(如 PEM)存储,或在编码过程中出现错误。可以使用以下命令尝试转换证书格式: ```bash openssl x509 -inform DER -in certificate.der -out certificate.pem ``` 6. **Python 环境中的 SSL 验证行为差异** 不同版本的 Python 对 SSL 证书的处理方式存在差异,例如 Python 3.6 的 SSL 验证较为宽松,而 3.7 及以上版本对证书链的完整性要求更严格。对于私有仓库,建议将根证书手动添加到系统信任库或 Python 的 `certifi` 包中。 ```python import ssl import urllib.request ssl_context = ssl.create_default_context(cafile="/path/to/custom-ca.pem") response = urllib.request.urlopen("https://your-private-repo.com", context=ssl_context) ``` 上述代码将自定义证书文件 `custom-ca.pem` 用于 SSL 验证,绕过系统默认的信任库。 ### 解决方案总结 - 确认证书的 RSA 密钥长度和签名算法符合现代安全标准。 - 验证证书链是否完整,必要时添加缺失的中间证书。 - 检查证书是否过期或系统时间是否正确。 - 调整 OpenSSL 配置以支持所需的加密算法。 - 对于 Python 环境,考虑使用自定义 CA 证书文件或降级到较宽松的版本(如 3.6)进行测试。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值