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.(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)检测到更早的文件结尾,私钥不正确。
自己写了一个生成秘钥对的代码,发现私钥的长度不正确,文档中的私钥是错误的,应该是私钥长度过长,在编辑文档的时只截取了部分私钥。
RSA ERROR_第1张图片
1.3 解决方法:
更改秘钥。

2. IOException: algid parse error, not a sequence

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

	static String publicKeyA;
	static String privateKeyA;
 
	static {
        try {
            Map 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.(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)); 

RSA ERROR_第2张图片

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;
}

结果

你可能感兴趣的:(安全)