【发布时间】:2014-06-02 14:32:55
【问题描述】:
我需要实现登录到 .NET Soap Web 服务。这个 Web Service 有方法
AuthenticateUser(username, password)
和密码应该用 RSA 公钥加密。下面是我想要做的:
public static final String PUBLIC = "q/9CujExqL6rsMMO22WWIotoXDCw5KEmGQJqL9UJEfoErwZ9ZCm3OwMTSlAMSfoXEMA04Y1rhfYC3MtU/7dYEoREfsvOPGDBWanTKyMzv2otCfiURyQoghEdkhv3ipQQaaErT7lfBKobJsdqJlvxo4PCOUas2Z6YpoMYgthzTiM=";
public static final String EXPONENT = "AQAB";
public static PublicKey getPublicKey() throws Exception{
byte[] modulusBytes = Base64.decode(PUBLIC, 0);
byte[] exponentBytes = Base64.decode(EXPONENT, 0);
BigInteger modulus = new BigInteger(1, (modulusBytes) );
BigInteger exponent = new BigInteger(1, (exponentBytes));
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
public static byte[] encrypt(Key publicKey, String s) throws Exception{
byte[] byteData = s.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(byteData);
return encryptedData;
}
public static String arrayAsString (byte [] array){
String p = "";
for (int i = 0; i < array.length; i++) {
p += unsignedToBytes(array[i]);
if (i < array.length - 1)
p+= ",";
}
return p;
}
public static int unsignedToBytes(byte b) {
return b & 0xFF;
}
public static void main(String[] args){
PublicKey publicKey = getPublicKey();
byte [] encrypted = encode(publicKey, "passwordHere");
String pass = arrayAsString(encrypted);
webservice.AuthenticateUser("testAdmin", pass);
}
我也有来自 Web 服务端的 .NET 代码
private static string publicKey = "<RSAKeyValue><Modulus>q/9CujExqL6rsMMO22WWIotoXDCw5KEmGQJqL9UJEfoErwZ9ZCm3OwMTSlAMSfoXEMA04Y1rhfYC3MtU/7dYEoREfsvOPGDBWanTKyMzv2otCfiURyQoghEdkhv3ipQQaaErT7lfBKobJsdqJlvxo4PCOUas2Z6YpoMYgthzTiM=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
private static UnicodeEncoding _encoder = new UnicodeEncoding();
public static string Encrypt(string data)
{
var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(publicKey);
var dataToEncrypt = _encoder.GetBytes(data);
var encryptedByteArray = rsa.Encrypt(dataToEncrypt, false).ToArray();
var length = encryptedByteArray.Count();
var item = 0;
var sb = new StringBuilder();
foreach (var x in encryptedByteArray)
{
item++;
sb.Append(x);
if (item < length)
sb.Append(",");
}
return sb.ToString();
}
public static string Decrypt(string data)
{
var rsa = new RSACryptoServiceProvider();
var dataArray = data.Split(new char[] { ',' });
byte[] dataByte = new byte[dataArray.Length];
for (int i = 0; i < dataArray.Length; i++)
{
dataByte[i] = Convert.ToByte(dataArray[i]);
}
rsa.FromXmlString(privateKey);
var decryptedByte = rsa.Decrypt(dataByte, false);
return _encoder.GetString(decryptedByte);
}
有人知道我做错了什么吗?为什么 Web 服务总是返回我 AuthenticateUserResponse{AuthenticateUserResult=false; }
【问题讨论】:
-
你试过调试你的网络服务吗?服务端
Decrypt的输出和客户端加密的数据一样吗?除此之外,我认为这里真正的问题是你正在推出自己的加密协议。我的建议是让 web 服务只能通过 SSL 访问,这应该可以减轻您现在使用的代码中的不安全性(例如没有重放保护的事实)。 -
感谢您的回复。不幸的是,我无法访问 Web 服务端,因为这是第 3 方 Web 服务,我无法检查输出,也无法更改安全性。你是什么意思“你正在滚动你自己的加密协议”?
标签: java .net encryption rsa public-key