简体   繁体   English

在Java中发送rc4加密的api调用

[英]sending rc4 encrypted api call in java

I am trying to make an api call in java using these steps: 我正在尝试使用以下步骤在Java中进行api调用:

  1. json encode json编码
  2. RC4 encryption RC4加密
  3. base64 encoding base64编码

I am currently using the same system in php and its working correctly: 我目前在php中使用相同的系统,其工作正常:

$enc_request = base64_encode(openssl_encrypt(json_encode($request_params), "rc4", $this->_app_key));

But when I use the same system in java, the results are not as expected. 但是,当我在Java中使用相同的系统时,结果却不符合预期。 Here's my code: 这是我的代码:

//json encoding
JSONObject obj = new JSONObject();
obj.put("email", username);
obj.put("password", password);
obj.put("action", "login");

//function to encode base64
private String getBase64Encoded(String encryptedJsonString)
{
    byte[] encoded = Base64.encodeBase64(encryptedJsonString.getBytes());

    String encodedString = new String(encoded);

    return encodedString;
}

//function to encrypt in RC4
private String getRC4EncryptedString2(String string, String key) throws Exception
{
    Cipher cipher = Cipher.getInstance("RC4");
    SecretKeySpec rc4Key = new SecretKeySpec(key.getBytes(), "RC4");
    cipher.init(Cipher.ENCRYPT_MODE, rc4Key);

    byte[] cipherText = cipher.update(string.getBytes());

    return new String(cipherText);
}

I was able to identify the problem upto the RC4 encryption which is not returning the same result as the php version. 我能够确定直到RC4加密为止的问题,该问题未返回与php版本相同的结果。

I've been battling this for 2 days now. 我已经为此战斗了两天。 I hope I have not missed any stupid thing because this should be straight-forward. 我希望我不会错过任何愚蠢的事情,因为这应该很简单。

Thanks 谢谢

You should use a byte[] not a String to hold intermediate byte array values. 您应该使用byte[]而不是String来保存中间字节数组值。 A String is for text, not raw data, and will attempt to decode the bytes as character data using your system's default character set (at least, the single-parameter String constructor will). String用于文本,而不是原始数据,并且将尝试使用系统的默认字符集将字节解码为字符数据(至少,单参数String构造函数会这样做)。 Same with String.getBytes() . String.getBytes()相同。

Just return cipherText directly from getRC4EncryptedString2() , and pass it directly to getBase64Encoded() . 只需直接从getRC4EncryptedString2()返回cipherText ,然后将其直接传递给getBase64Encoded() There's a reason those encoders operate on byte arrays, and that reason is not so that you can garble the data by applying a character encoding to it in between. 这些编码器在字节数组上进行操作是有原因的,但并非如此,因此您可以通过在两者之间应用字符编码来乱码数据。

The same goes for the key you are passing to getRC4EncryptedString2() . 传递给getRC4EncryptedString2()的密钥也是getRC4EncryptedString2() At the bare minimum use String.getBytes("ISO-8859-1") or something (assuming that your key is actually text and not yet another garbled byte array). 至少要使用String.getBytes("ISO-8859-1")或其他东西(假设您的键实际上是文本,而不是另一个乱码字节数组)。 The no-parameter version of getBytes() returns the text encoded using your system's default character set, which is not guaranteed to be what you want. getBytes()的无参数版本返回使用系统默认字符集编码的文本,但不能保证是您想要的文本。

That also all applies to the String you are returning from your base 64 encoder. 这也适用于您从base 64编码器返回的String I don't know what base 64 encoder you are using, but make sure you specify the character set to the String constructor. 我不知道您使用的是哪种base 64编码器,但是请确保将字符集指定为String构造函数。 Most likely you will be OK, purely by coincidence, but you should always specify a character set when converting to/from String and raw bytes. 纯粹出于巧合,您很可能会没事,但是在与String和原始字节进行相互转换时,应始终指定一个字符集。 And that, of course, assumes that your base 64 encoder returns text, rather than bytes in the range 0-63. 并且,当然,假设您的base 64编码器返回文本,而不是0-63范围内的字节。

The general point here is you can't just convert back and forth from String to byte[] . 这里的一般要点是您不能只是从Stringbyte[]来回转换。 A String is for text and it's representation as a byte[] depends on the character encoding. String用于文本,其表示形式为byte[]取决于字符编码。

I am able to achieve this using the following code. 我可以使用以下代码来实现。 Hope this helps! 希望这可以帮助!

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import org.apache.commons.codec.DecoderException;
import org.bouncycastle.util.encoders.Hex;
import org.json.JSONException;
import org.json.JSONObject;

public class RC4Algo {

    public static void main(String args[])throws IOException, NoSuchAlgorithmException, DecoderException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, JSONException
    {
        decryptRC4();
    }

    static String decryptRC4() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, JSONException{

        //byte[] plainBytes = "testString".getBytes();

        //json encoding
        JSONObject obj = new JSONObject();
        obj.put("email", "username");
        obj.put("password", "password");
        obj.put("action", "login");

        byte [] plainBytes = obj.toString().getBytes();

        String hashedKey = hashedData("thisismysecretkey");

        //Generate a new key using KeyGenerator
        /*KeyGenerator rc4KeyGenerator = KeyGenerator.getInstance("RC4");
        SecretKey key = rc4KeyGenerator.generateKey();*/

        Key key = new SecretKeySpec(Hex.decode(hashedKey), "RC4");

        // Create Cipher instance and initialize it to encrytion mode
        Cipher cipher = Cipher.getInstance("RC4");  // Transformation of the algorithm
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] cipherBytes = cipher.doFinal(plainBytes);

        String encoded = encodeBase64(cipherBytes);

        String decoded = decodeBase64(encoded);

        // Reinitialize the Cipher to decryption mode
        cipher.init(Cipher.DECRYPT_MODE,key, cipher.getParameters());
        byte[] plainBytesDecrypted = cipher.doFinal(Hex.decode(decoded));

        System.out.println("Decrypted Data : "+new String(plainBytesDecrypted));
        return new String(plainBytesDecrypted);
    }

    static String decodeBase64(String encodedData){
        byte[] b = Base64.getDecoder().decode(encodedData);
        String decodedData = DatatypeConverter.printHexBinary(b);
        return decodedData;
    }

    static String encodeBase64(byte[] data){
        byte[] b = Base64.getEncoder().encode(data);
        String encodedData = new String(b);
        /*String encodedData = DatatypeConverter.printHexBinary(b);*/
        return encodedData;
    }

    static String hashedData(String key) throws NoSuchAlgorithmException{
        String password = key;

        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(password.getBytes());

        byte byteData[] = md.digest();

        //convert the byte to hex format method 1
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < byteData.length; i++) {
         sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
        }

        //convert the byte to hex format method 2
        StringBuffer hexString = new StringBuffer();
        for (int i=0;i<byteData.length;i++) {
            String hex=Integer.toHexString(0xff & byteData[i]);
            if(hex.length()==1) hexString.append('0');
            hexString.append(hex);
        }
        return hexString.toString();
    }

    }

Output: 输出:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM