2011-08-24 90 views
1

我必須加密字符串通過HTTPS發送到服務器。然後,在服務器端,我必須解密字符串並使用它。Android:加密字符串,通過HTTPS發送和解密字符串問題

我用這個代碼在兩側:

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 = "ABCDEF"; 

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

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

} 

在Android,使用 「123456789」 作爲種子的rawKey給我:

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

但是在服務器端,使用相同的種子,給我:

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

我不明白爲什麼。 Android上的javax.crypto.KeyGenerator是不同的嗎?,我做的不好?

請,我需要一些幫助。

非常感謝您

對不起,我的英文不好

----------------------------- 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代碼工作正常!--------------------------------

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; 
    }  
} 

回答

2

爲什麼要加密如果您首先使用SSL? HTTPS(SSL)將在傳輸中加密您的數據,並且它將在服務器上自動解密。此外,您的自定義加密方案很可能不如SSL安全。

你的錯誤是在你如何派生你的密鑰:setSeed()並不取代隨機數發生器的狀態,它只是增加它。這意味着即使您將相同的字節傳遞給setSeed()generateKey()也很可能會生成不同的密鑰。使用PBE(基於密碼的加密)類從密碼派生密鑰。或者確保您的服務器和客戶端以其他方式使用相同的密鑰。

這裏是一個從密碼生成密鑰的示例(適用於Android)。您需要找到在Android和您的服務器上都支持的PBE算法。如果您在服務器應用程序中使用JCE Bouncy Castle提供程序,那麼它應該支持與Android相同的算法(Android爲JCE實現的一部分使用Bouncy Castle)。

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"); 
+0

感謝您的回答。我會測試它 我想加密字符串becouse在Android中,SSL/HTTPS它不工作得很好。我必須制定一種方法來信任所有主機,所以我想對其進行加密以獲得額外的安全性。 再次感謝 –

+0

你有使用PBE的例子嗎?請 –

+0

您不必信任所有主機,只需將服務器證書安裝到您的應用程序中即可。如何做到這一點已經在SO上回答了一千次。 –