【问题标题】:RSA. Java Encryption .NET DecryptionRSA。 Java 加密 .NET 解密
【发布时间】: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


【解决方案1】:

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

【讨论】:

  • 试过了,还是不行。我认为有两件事,我可能会搞砸。首先 - java 字节有符号,.NET 字节无符号。我做转换 - unsignedToBytes,但也许我做错了地方?第二 - 字节数组字节序。据我了解,java 使用 BigEndian,.NET 使用 little endian。这意味着在字节数组的情况下,这只是恢复的数组,我试图恢复加密结果,但它也不起作用。谢谢。
  • @GeorgyGobozov 我认为这仍然是一个编码问题 - Java 中的默认 UTF-16 编码添加了一个字节顺序标记,.NET UnicodeEncoding 没有预料到它会破坏输出。您需要使用UTF-16LE 作为Java 中的编码。我已经能够成功地在 Java 中对字符串进行编码并在 .NET 中进行解码,这种编码用于将密码转换为 Java 中的字节数组。
  • 就是这样!我刚刚在 UTF-16LE 上更改了 UTF-8 并且它有效!感谢您的帮助,不胜感激!
猜你喜欢
  • 1970-01-01
  • 2011-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-10
  • 2016-10-14
  • 2014-07-12
  • 2011-08-06
相关资源
最近更新 更多