Android:加密字符串,通过HTTPS和Decrypt字符串发送问题 [英] Android: Encrypt String, send via HTTPS and Decrypt String problem

查看:103
本文介绍了Android:加密字符串,通过HTTPS和Decrypt字符串发送问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须加密字符串以通过HTTPS发送到服务器。然后,在服务器端,我必须解密字符串并使用它。

I have to Encrypt a String to send via HTTPS to a server. Then, on server side, I have to Decrypt the string and used it.

我在双方都使用了这个代码:

I used this code in both sides:

public class SimpleCrypto {

public static String encrypt(String seed, String cleartext) throws Exception {

    byte[] rawKey = getRawKey(seed.getBytes());

    byte[] result = encrypt(rawKey, cleartext.getBytes());

    return toHex(result);
}

public static String decrypt(String seed, String encrypted) throws Exception {

    byte[] rawKey = getRawKey(seed.getBytes());

    byte[] enc = toByte(encrypted);

    byte[] result = decrypt(rawKey, enc);

    return new String(result);
}

private static byte[] getRawKey(byte[] seed) throws Exception {

    KeyGenerator kgen = KeyGenerator.getInstance("AES");

    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");

    sr.setSeed(seed);

    kgen.init(128, sr); // 192 and 256 bits may not be available

    SecretKey skey = kgen.generateKey();

    byte[] raw = skey.getEncoded();

    return raw;
}


private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {

    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

    Cipher cipher = Cipher.getInstance("AES");

    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

    byte[] encrypted = cipher.doFinal(clear);

    return encrypted;
}

private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {

    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

    Cipher cipher = Cipher.getInstance("AES");

    cipher.init(Cipher.DECRYPT_MODE, skeySpec);

    byte[] decrypted = cipher.doFinal(encrypted);

    return decrypted;
}

public static String toHex(String txt) {

    return toHex(txt.getBytes());
}
public static String fromHex(String hex) {

    return new String(toByte(hex));
}

public static byte[] toByte(String hexString) {

    int len = hexString.length()/2;

    byte[] result = new byte[len];

    for (int i = 0; i < len; i++)
        result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();

    return result;
}

public static String toHex(byte[] buf) {

    if (buf == null)
        return "";

    StringBuffer result = new StringBuffer(2*buf.length);

    for (int i = 0; i < buf.length; i++) {
            appendHex(result, buf[i]);
    }

    return result.toString();
}

private final static String HEX = "0123456789ABCDEF";

private static void appendHex(StringBuffer sb, byte b) {

    sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}

}

在Android上,使用123456789作为种子,rawKey给我:

On android, using "123456789" as a seed the rawKey give me:

[99,51,-103,-58,81,-52,90,-103,-114,70, - 128,-25,-105,-124,-128,-67]

[99, 51, -103, -58, 81, -52, 90, -103, -114, 70, -128, -25, -105, -124, -128, -67]

但在服务器端,使用相同的种子,请给我:

But on Server side, using the same seed, give me:

[ - 52,103,4,60,123,-49,-11,-18,-91,86,107,-39,-79,-13,-57, 79]

[-52, 103, 4, 60, 123, -49, -11, -18, -91, 86, 107, -39, -79, -13, -57, 79]

我无法理解为什么。与Android上的javax.crypto.KeyGenerator不同吗?我做错了什么?

I can't understand why. Is diferent the javax.crypto.KeyGenerator on Android?, I'm making something bad?

请,我需要一些帮助。

非常感谢

抱歉我的英语不好

----- ------------------------ UPDATE ------------------------- -------------------------------

-----------------------------UPDATE--------------------------------------------------------

这是我的新作品代码:

public class DesEncrypter {

    public static final int SALT_LENGTH = 20;
    public static final int PBE_ITERATION_COUNT = 1024;

    private static final String RANDOM_ALGORITHM = "SHA1PRNG";
    private static final String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";


    public byte[] encrypt(String password, String cleartext) {

        byte[] encryptedText = null;

        try {
            byte[] salt = "dfghjklpoiuytgftgyhj".getBytes();

            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, PBE_ITERATION_COUNT, 256);

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHAAND256BITAES-CBC-BC");

            SecretKey tmp = factory.generateSecret(pbeKeySpec);

            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            byte[] key = secret.getEncoded();

            Cipher encryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM);   

            byte[] iv = generateIv();

            IvParameterSpec ivspec = new IvParameterSpec(iv);

            encryptionCipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);

            encryptedText = encryptionCipher.doFinal(cleartext.getBytes());

        } catch (Exception e) {
            e.printStackTrace();
        }

        return encryptedText;
    }

    public String decrypt(String password, byte[] encryptedText) {

        String cleartext = "";

        try {
            byte[] salt = "dfghjklpoiuytgftgyhj".getBytes();

            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, PBE_ITERATION_COUNT, 256);

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHAAND256BITAES-CBC-BC");

            SecretKey tmp = factory.generateSecret(pbeKeySpec);

            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            byte[] key = secret.getEncoded();

            Cipher decryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM);

            byte[] iv = generateIv();

            IvParameterSpec ivspec = new IvParameterSpec(iv);

            decryptionCipher.init(Cipher.DECRYPT_MODE, secret, ivspec);

            byte[] decryptedText = decryptionCipher.doFinal(encryptedText);

            cleartext =  new String(decryptedText); 

        } catch (Exception e) {
            e.printStackTrace();
        }

        return cleartext;
    }   

    private byte[] generateIv() throws NoSuchAlgorithmException {

        SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);

        byte[] iv = new byte[16];

        random.nextBytes(iv);

        return iv;
    }

}

------- ---------------------最终代码在ANDROID上工作!----------------------- ---------

----------------------------FINALL CODE WORKING ON ANDROID!--------------------------------

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class DesEncrypter {

    public static final int SALT_LENGTH = 20;
    public static final int PBE_ITERATION_COUNT = 200; //1024;

    private static final String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";

    //algoritmo / modo / relleno 
    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";

    byte[] iv = "1234567890asdfgh".getBytes();

    byte[] salt = "dfghjklpoiuytgftgyhj".getBytes();

    public byte[] encrypt(String password, String cleartext) {

        byte[] encryptedText = null;

        try {


            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, PBE_ITERATION_COUNT, 256);

            //Factoria para crear la SecretKey, debemos indicar el Algoritmo
            SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_ALGORITHM);

            SecretKey tmp = factory.generateSecret(pbeKeySpec);

            //Creamos una llave;
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            //Obtenemos la llave, solo informativo
            byte[] key = secret.getEncoded();

            //La clase Cipher, se usa para cifrar mediante algoritmos de  clave simétrica
            Cipher encryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM);   

            //byte[] iv = generateIv();

            IvParameterSpec ivspec = new IvParameterSpec(iv);

            //Accion, SecretKey, parameter specification for an initialization vector
            encryptionCipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);

            //Realizamos el cifrado
            encryptedText = encryptionCipher.doFinal(cleartext.getBytes());

        } catch (Exception e) {
            e.printStackTrace();
        }

        return encryptedText;
    }

    public String decrypt(String password, byte[] encryptedText) {

        String cleartext = "";

        try {

            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, PBE_ITERATION_COUNT, 256);

            //Factoria para crear la SecretKey, debemos indicar el Algoritmo
            SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_ALGORITHM);

            SecretKey tmp = factory.generateSecret(pbeKeySpec);

            //Creamos una llave;
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            //Obtenemos la llave, solo informativo
            byte[] key = secret.getEncoded();

            //La clase Cipher, se usa para cifrar mediante algoritmos de  clave simétrica
            Cipher decryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM);

            //byte[] iv = generateIv();

            IvParameterSpec ivspec = new IvParameterSpec(iv);

            //Accion, SecretKey, parameter specification for an initialization vector
            decryptionCipher.init(Cipher.DECRYPT_MODE, secret, ivspec);

            //Realizamos el descifrado
            byte[] decryptedText = decryptionCipher.doFinal(encryptedText);

            cleartext =  new String(decryptedText); 

        } catch (Exception e) {
            e.printStackTrace();
        }

        return cleartext;
    }      
}


推荐答案

为什么如果你首先使用SSL,你在加密吗? HTTPS(SSL)将对传输中的数据进行加密,并在服务器上自动解密。此外,您的自定义加密方案很可能不如SSL安全。

Why are you encrypting if you are using SSL in the first place? HTTPS (SSL) will encrypt your data in transit, and it will be automatically decrypted on the server. Additionally, your custom encryption scheme is very likely to be less secure than SSL.

您的错误在于如何推导您的密钥: setSeed() 不会替换随机数生成器的状态,只会增加它。这意味着即使你将相同的字节传递给 setSeed() generateKey()也很可能会生成一把不同的钥匙。使用 PBE (基于密码的加密)类来派生来自密码的密钥。或者确保您的服务器和客户端以其他方式使用相同的密钥。

Your error is in how you derive your key: setSeed() does not replace the state of the random number generator, it only augment it. What this means is that even if you pass the same bytes to setSeed(), generateKey() will most likely generate a different key. Use the PBE (password-based encryption) classes to derive a key from a password. Or make sure your server and client are using the same key in some other way.

这里有一个从密码生成密钥的示例(适用于Android)。您需要找到Android和服务器上都支持的PBE算法。如果您在服务器应用程序中使用JCE Bouncy Castle提供程序,它应该支持与Android相同的算法(Android使用Bouncy Castle作为其部分JCE实现)。

Here a sample of generating a key from a password (for Android). You need to find a PBE algorithm that is supported both on Android and on your server. If you use the JCE Bouncy Castle provider in your server app, it should support the same algorithms as Android (Android uses Bouncy Castle for part of its JCE implementation).

SecretKeyFactory factory = 
    SecretKeyFactory.getInstance("PBEWITHSHAAND256BITAES-CBC-BC");
KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

这篇关于Android:加密字符串,通过HTTPS和Decrypt字符串发送问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆