2014-04-18 74 views
0

我需要实现登录到.NET Soap Web Service。此Web服务具有方法RSA。 Java Encryption .NET解密

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 Service总是返回我AuthenticateUserResponse {AuthenticateUserResult = false; }

+0

你有没有试过调试你的web服务?服务端的Decrypt输出是否与客户端加密的数据相同?除此之外,我认为这里真正的问题是您正在推出自己的加密协议。我的建议是只能通过SSL访问web服务,这样可以缓解您现在使用的代码中的不安全感(比如没有重播保护)。 – Iridium

+0

感谢您的回复。不幸的是,我无法访问web服务端,因为这是第三方web服务,我无法检查输出并且无法更改安全性。你是什​​么意思“你正在推出你自己的加密协议”? –

回答

1

我认为这里的问题可能是文本编码,而不是加密/解密过程本身。在Java方面,您正在加密UTF-8编码的密码,而在.NET方面,它使用的是UTF-16的UnicodeEncoding。改为在加密之前尝试在Java端使用UTF-16。

+0

试过了,仍然不起作用。我认为有两件事情,我可能会搞砸。首先 - java字节签名,.NET字节无符号。我做转换 - unsignedToBytes,但也许我做错了地方?第二个字节数组endian。据我了解java使用BigEndian,.NET使用小端。这意味着在字节数组的情况下,这只是返回数组,我试图恢复加密结果,但它也不起作用。谢谢。 –

+0

@GeorgyGobozov我认为它仍然是一个编码问题 - Java中默认的UTF-16编码增加了一个字节顺序标记,.NET UnicodeEncoding并不期望并破坏输出。您需要使用'UTF-16LE'作为Java中的编码。我已经能够在Java中成功编码一个字符串,并在.NET中进行解码,并使用该编码将密码转换为Java中的字节数组。 – Iridium

+0

就是这样!我只是更改了UTF-16LE上的UTF-8,它工作正常!感谢您的帮助,感谢! –