这周用了三天的时间学WebService,第一天在网上找资料认识WebService,第二天早上的时候自己发布了WebService,学习了注解,并成功的访问到了发布的WSDL。余下的一天半左右用在了学习SRA,第一次接触SRA是在大三上学期信息安全的课上,当时也实现了SRA算法并且印象中没有遇到什么bug,这次遇到了一些,记录一下。
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)检测到更早的文件结尾,私钥不正确。
自己写了一个生成秘钥对的代码,发现私钥的长度不正确,文档中的私钥是错误的,应该是私钥长度过长,在编辑文档的时只截取了部分私钥。
1.3 解决方法:
更改秘钥。
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.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;
}