Mã hóa / giải mã Android bằng AES [đã đóng]


105

Có ví dụ điển hình nào về cách mã hóa và giải mã hình ảnh và các tệp khác bằng AES trên Android không?


7
Mã hóa trên Android về cơ bản không khác so với bất kỳ nền tảng Java SE nào khác. Và vì tất cả các câu trả lời bên dưới đều không an toàn, vì bạn phải hiểu mật mã trước khi bắt đầu triển khai hoặc mượn các ví dụ về mật mã.
Maarten Bodewes

4
Bạn nên thử github.com/facebook/conceal này .
Nhat Dinh,

Câu trả lời:


131

Cảnh báo: Câu trả lời này chứa mã bạn không nên sử dụng vì nó không an toàn (sử dụng SHA1PRNG để lấy khóa và sử dụng AES ở chế độ ECB)

Thay vào đó (kể từ năm 2016), hãy sử dụng PBKDF2WithHmacSHA1 để lấy khóa và AES ở chế độ CBC hoặc GCM (GCM cung cấp cả quyền riêng tư và tính toàn vẹn)

Bạn có thể sử dụng các chức năng như sau:

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

Và gọi chúng như thế này:

ByteArrayOutputStream baos = new ByteArrayOutputStream();  
bm.compress(Bitmap.CompressFormat.PNG, 100, baos); // bm is the bitmap object   
byte[] b = baos.toByteArray();  

byte[] keyStart = "this is a key".getBytes();
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(keyStart);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();    

// encrypt
byte[] encryptedData = encrypt(key,b);
// decrypt
byte[] decryptedData = decrypt(key,encryptedData);

Điều này sẽ hoạt động, tôi sử dụng mã tương tự trong một dự án ngay bây giờ.


9
Này, điều này không hiệu quả với tôi, tôi nhận được ngoại lệ Badpadding trong khi giải mã giống nhau.
Sanat Pandey

34
CẢNH BÁO Mã này đang sử dụng mã xấu đã biết từ các đoạn mã của Android để lấy khóa. Không sử dụng nó trừ khi bạn muốn mất dữ liệu của mình. Một RNG được gieo hạt không phải là một Chức năng Tạo nguồn Chính (KDF) tốt.
Maarten Bodewes

2
@IcedDante Vui lòng xem câu hỏi này .
Maarten Bodewes

35
CẢNH BÁO Mã này có thể mặc định là mã hóa chế độ ECB trên hầu hết các nền tảng. Sử dụng mã hóa chế độ ECB không an toàn cho hầu hết dữ liệu, chứ đừng nói đến ảnh. Tìm chim cánh cụt !
Maarten Bodewes

10
@Maarten Bodewes Tôi thấy cảnh báo của bạn ở khắp nơi, dưới nhiều bài đăng. Bạn có thể vui lòng cung cấp một giải pháp tốt thay thế không?
Yar

16

Như đã đề cập bởi Nacho.L PBKDF2WithHmacSHA1 dẫn xuất được sử dụng vì nó được bảo mật hơn.

import android.util.Base64;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

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

public class AESEncyption {

    private static final int pswdIterations = 10;
    private static final int keySize = 128;
    private static final String cypherInstance = "AES/CBC/PKCS5Padding";
    private static final String secretKeyInstance = "PBKDF2WithHmacSHA1";
    private static final String plainText = "sampleText";
    private static final String AESSalt = "exampleSalt";
    private static final String initializationVector = "8119745113154120";

    public static String encrypt(String textToEncrypt) throws Exception {

        SecretKeySpec skeySpec = new SecretKeySpec(getRaw(plainText, AESSalt), "AES");
        Cipher cipher = Cipher.getInstance(cypherInstance);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(initializationVector.getBytes()));
        byte[] encrypted = cipher.doFinal(textToEncrypt.getBytes());
        return Base64.encodeToString(encrypted, Base64.DEFAULT);
    }

    public static String decrypt(String textToDecrypt) throws Exception {

        byte[] encryted_bytes = Base64.decode(textToDecrypt, Base64.DEFAULT);
        SecretKeySpec skeySpec = new SecretKeySpec(getRaw(plainText, AESSalt), "AES");
        Cipher cipher = Cipher.getInstance(cypherInstance);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(initializationVector.getBytes()));
        byte[] decrypted = cipher.doFinal(encryted_bytes);
        return new String(decrypted, "UTF-8");
    }

    private static byte[] getRaw(String plainText, String salt) {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance(secretKeyInstance);
            KeySpec spec = new PBEKeySpec(plainText.toCharArray(), salt.getBytes(), pswdIterations, keySize);
            return factory.generateSecret(spec).getEncoded();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return new byte[0];
    }

}

2
Đúng là dẫn xuất này tốt hơn nhiều. Nhưng bây giờ bạn đang sử dụng IV tĩnh, một muối tĩnh và số lần lặp lại quá thấp. Vì vậy, không có cảnh báo, kết quả vẫn không an toàn. Tiền điện tử là một nỗi đau để đi đúng ...
Maarten Bodewes vào

13
import java.security.AlgorithmParameters;
import java.security.SecureRandom;
import java.security.spec.KeySpec;

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

class SecurityUtils {

  private static final byte[] salt = { (byte) 0xA4, (byte) 0x0B, (byte) 0xC8,
      (byte) 0x34, (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13 };

  private static int BLOCKS = 128;

  public static byte[] encryptAES(String seed, String cleartext)
      throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes("UTF8"));
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    return cipher.doFinal(cleartext.getBytes("UTF8"));
  }

  public static byte[] decryptAES(String seed, byte[] data) throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes("UTF8"));
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    return cipher.doFinal(data);
  }

  private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    sr.setSeed(seed);
    kgen.init(BLOCKS, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
  }

  private static byte[] pad(byte[] seed) {
    byte[] nseed = new byte[BLOCKS / 8];
    for (int i = 0; i < BLOCKS / 8; i++)
      nseed[i] = 0;
    for (int i = 0; i < seed.length; i++)
      nseed[i] = seed[i];

    return nseed;
  }

  public static byte[] encryptPBE(String password, String cleartext)
      throws Exception {
    SecretKeyFactory factory = SecretKeyFactory
        .getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1024, 256);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();
    byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
    return cipher.doFinal(cleartext.getBytes("UTF-8"));
  }

  public static String decryptPBE(SecretKey secret, String ciphertext,
      byte[] iv) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
    return new String(cipher.doFinal(ciphertext.getBytes()), "UTF-8");
  }

}

4
Đoạn mã trên ném BadPaddingException trên Android 4.2
Brijesh Thakur

1
@BrijeshThakur - đọc cái này
t0mm13b

12
CẢNH BÁO Mã này đang sử dụng mã xấu đã biết từ Android Snippets để lấy khóa. Không sử dụng nó trừ khi bạn muốn mất dữ liệu của mình. Một RNG được gieo hạt không phải là một Chức năng Tạo nguồn Chính (KDF) tốt.
Maarten Bodewes

3
Thông tin thêm ở đây
Maarten Bodewes

9
CẢNH BÁO Mã này có thể mặc định là mã hóa chế độ ECB trên hầu hết các nền tảng. Sử dụng mã hóa chế độ ECB không an toàn cho hầu hết dữ liệu, chứ đừng nói đến ảnh. Tìm chim cánh cụt !
Maarten Bodewes

9

Câu hỏi cũ nhưng tôi nâng cấp các câu trả lời hỗ trợ Android trước và đăng 4.2 và xem xét tất cả các thay đổi gần đây theo blog của nhà phát triển Android

Thêm vào đó, tôi để lại một ví dụ hoạt động trên github repo của mình .

import java.nio.charset.Charset;
import java.security.AlgorithmParameters;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;


/*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will Google be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, as long as the origin is not misrepresented.
* 
* @author: Ricardo Champa
* 
*/

public class MyCipher {

    private final static String ALGORITHM = "AES";
    private String mySecret;

    public MyCipher(String mySecret){
        this.mySecret = mySecret;
    }

    public MyCipherData encryptUTF8(String data){
        try{
            byte[] bytes = data.toString().getBytes("utf-8");
            byte[] bytesBase64 = Base64.encodeBase64(bytes);
            return encrypt(bytesBase64);
        }
        catch(Exception e){
            MyLogs.show(e.getMessage());
            return null;
        }

    }

    public String decryptUTF8(byte[] encryptedData, IvParameterSpec iv){
        try {
            byte[] decryptedData = decrypt(encryptedData, iv);
            byte[] decodedBytes = Base64.decodeBase64(decryptedData);
            String restored_data = new String(decodedBytes, Charset.forName("UTF8"));
            return restored_data;
        } catch (Exception e) {
            MyLogs.show(e.getMessage());;
            return null;
        }
    }

    //AES
    private MyCipherData encrypt(byte[] raw, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, ALGORITHM);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //solved using PRNGFixes class
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] data = cipher.doFinal(clear);

        AlgorithmParameters params = cipher.getParameters();
        byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        return new MyCipherData(data, iv);
    }

    private byte[] decrypt(byte[] raw, byte[] encrypted, IvParameterSpec iv) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, ALGORITHM);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
    }

    private byte[] getKey() throws Exception{
        byte[] keyStart = this.mySecret.getBytes("utf-8");
        KeyGenerator kgen = KeyGenerator.getInstance(ALGORITHM);

        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
        //      if (android.os.Build.VERSION.SDK_INT >= 17) {
        //          sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
        //      } else {
        //          sr = SecureRandom.getInstance("SHA1PRNG");
        //      }
        sr.setSeed(keyStart);
        kgen.init(128, sr); // 192 and 256 bits may not be available
        SecretKey skey = kgen.generateKey();
        byte[] key = skey.getEncoded();
        return key;

    }
    ////////////////////////////////////////////////////////////
    private MyCipherData encrypt(byte[] data) throws Exception{
        return encrypt(getKey(),data);
    }
    private byte[] decrypt(byte[] encryptedData, IvParameterSpec iv) throws Exception{
        return decrypt(getKey(),encryptedData, iv);
    }
}


@HammadTariqSahi? ¿
Ricardo

Thay vì sử dụng thư viện Apache Commons Codec, có bất kỳ điều gì bất lợi khi sử dụng android.util.Base64.encode(bytes, Base64.DEFAULT)android.util.Base64.decode(decryptedData, Base64.DEFAULT)?
ban-geoengineering

2
CẢNH BÁO Mã này đang sử dụng mã xấu đã biết từ Android Snippets để lấy khóa. Không sử dụng nó trừ khi bạn muốn mất dữ liệu của mình. Một RNG được gieo hạt không phải là một Chức năng Tạo nguồn Chính (KDF) tốt. (thở dài).
Maarten Bodewes

1
@MaartenBodewes tôi nên thực hiện những thay đổi nào?
Ricardo

7

Nếu bạn đang mã hóa một tệp văn bản, thì thử nghiệm / mẫu sau có thể hữu ích. Nó làm như sau:

  1. Tạo luồng byte,
  2. kết thúc điều đó bằng mã hóa AES,
  3. bọc nó tiếp theo với xử lý văn bản
  4. và cuối cùng đệm nó

    // AESdemo
    
    public class AESdemo extends Activity {
        boolean encryptionIsOn = true;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_aesdemo);
            // needs <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
            String homeDirName = Environment.getExternalStorageDirectory().getAbsolutePath() +
                    "/" + getPackageName();
            File file = new File(homeDirName, "test.txt");
            byte[] keyBytes = getKey("password");
    
            try {
                File dir = new File(homeDirName);
                if (!dir.exists())
                    dir.mkdirs();
                if (!file.exists())
                    file.createNewFile();
    
                OutputStreamWriter osw;
    
                if (encryptionIsOn) {
                    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
                    IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
                    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
    
                    FileOutputStream fos = new FileOutputStream(file);
                    CipherOutputStream cos = new CipherOutputStream(fos, cipher);
                    osw = new OutputStreamWriter(cos, "UTF-8");
                }
                else    // not encryptionIsOn
                    osw = new FileWriter(file);
    
                BufferedWriter out = new BufferedWriter(osw);
                out.write("This is a test\n");
                out.close();
            }
            catch (Exception e) {
                System.out.println("Encryption Exception "+e);
            }
    
            ///////////////////////////////////
            try {
                InputStreamReader isr;
    
                if (encryptionIsOn) {
                    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
                    IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
                    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
    
                    FileInputStream fis = new FileInputStream(file);
                    CipherInputStream cis = new CipherInputStream(fis, cipher);
                    isr = new InputStreamReader(cis, "UTF-8");
                }
                else
                    isr = new FileReader(file);
    
                BufferedReader in = new BufferedReader(isr);
                String line = in.readLine();
                System.out.println("Text read: <"+line+">");
                in.close();
            }
            catch (Exception e) {
                System.out.println("Decryption Exception "+e);
            }
        }
    
        private byte[] getKey(String password) throws UnsupportedEncodingException {
            String key = "";
            while (key.length() < 16)
                key += password;
            return key.substring(0, 16).getBytes("UTF-8");
        }
    }

8
CẢNH BÁO Mã này đang sử dụng cơ chế dẫn xuất khóa sử dụng giải mã ký tự mặc định. Không sử dụng điều này trừ khi bạn muốn gặp sự cố khi giải mã dữ liệu của mình.
Maarten Bodewes

3
@owlstead, quan sát tốt, sẽ rất tuyệt nếu bạn đề xuất bản sửa lỗi. Ví dụ trên hiện đã được cập nhật để chỉ định mã hóa ký tự trong getKey (). Chỉnh thêm được hoan nghênh ...
SoloPilot

9
Xin lỗi, tôi chủ yếu ghi câu trả lời ở đây, bởi vì chúng được sử dụng SecureRandomđể lấy khóa. Nếu bạn muốn biết cách khởi tạo mật mã, hãy xem câu trả lời của ericksons tại đây . Không sử dụng IV tĩnh (cho cùng một khóa) và sử dụng PBKDF2 để chuyển đổi mật khẩu -> khóa. Lưu ý rằng mật mã không được xác thực chỉ cung cấp tính bảo mật và chỉ khi nó không được sử dụng trong giao thức truyền tải. Nếu bạn muốn giúp đỡ, bạn có thể ghi các câu trả lời khác quá (và bỏ phiếu lên ý kiến của tôi ở đó) :)
Maarten Bodewes

@MaartenBodewes bạn đã "đốt cháy" nhiều câu trả lời, nhưng bạn không đề xuất câu trả lời. Nếu bạn có câu trả lời chính xác, tại sao bạn không viết một câu trả lời ở đây?
Dika

@Dika Tôi nghĩ rằng tôi đã chỉ ra một câu trả lời ở trên. Xin lưu ý rằng tôi có lợi nhuận rất lớn là người đăng nhiều câu trả lời nhất về cả mật mã và mã hóa. Cũng nên nhớ rằng tôi khá phản đối các thư viện trình bao bọc chung chung chỉ dẫn mọi người sao chép mã hơn là tự viết mã cho một trường hợp sử dụng cụ thể. API tiền điện tử Java được nghĩ ra khá tốt, nếu hơi rườm rà. Sử dụng nó! Không có gì đặc biệt về mã hóa hình ảnh; đó là mã hóa tệp cơ bản.
Maarten Bodewes

5

Mã hóa / giải mã AES trong Android

String encData= encrypt("keykey".getBytes("UTF-16LE"), ("0123000000000215").getBytes("UTF-16LE"));

String decData= decrypt("keykey",Base64.decode(encData.getBytes("UTF-16LE"), Base64.DEFAULT));

mã hóa chức năng

private static String encrypt(byte[] key, byte[] clear) throws Exception
    {
        MessageDigest md = MessageDigest.getInstance("md5");
        byte[] digestOfPassword = md.digest(key);

        SecretKeySpec skeySpec = new SecretKeySpec(digestOfPassword, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(clear);
        return Base64.encodeToString(encrypted,Base64.DEFAULT);
    }

giải mã chức năng

private static String decrypt(String key, byte[] encrypted) throws Exception
    {
        MessageDigest md = MessageDigest.getInstance("md5");
        byte[] digestOfPassword = md.digest(key.getBytes("UTF-16LE"));

        SecretKeySpec skeySpec = new SecretKeySpec(digestOfPassword, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted, "UTF-16LE");
    }

Mã hóa / giải mã AES trong c #

 static void Main(string[] args)
        {
            string enc = encryptAES("0123000000000215", "keykey");
            string dec = decryptAES(enc, "keykey");

            Console.ReadKey();
        }

mã hóa chức năng

 public static string encryptAES(string input, string key)
        {
            var plain = Encoding.Unicode.GetBytes(input);

            // 128 bits
            AesCryptoServiceProvider provider = new AesCryptoServiceProvider();
            provider.KeySize = 128;
            provider.Mode = CipherMode.ECB;
            provider.Padding = PaddingMode.PKCS7;

            provider.Key = CalculateMD5Hash(key);

            var enc = provider.CreateEncryptor().TransformFinalBlock(plain, 0, plain.Length);
            return Convert.ToBase64String(enc);
        }

giải mã chức năng

public static string decryptAES(string encryptText, string key)
{
    byte[] enc = Convert.FromBase64String(encryptText);
    // 128 bits
    AesCryptoServiceProvider provider = new AesCryptoServiceProvider();
    provider.KeySize = 128;
    provider.Mode = CipherMode.ECB;
    provider.Padding = PaddingMode.PKCS7;

    provider.Key = CalculateMD5Hash(key);


    var dec = provider.CreateDecryptor().TransformFinalBlock(enc, 0, enc.Length);
    return Encoding.Unicode.GetString(dec);
}

tạo md5

 public static byte[] CalculateMD5Hash(string input)
        {
            MD5 md5 = MD5.Create();
            byte[] inputBytes = Encoding.Unicode.GetBytes(input);
            return md5.ComputeHash(inputBytes);
        }

1
MD5 không phải là hàm băm mật khẩu hoặc Chức năng lấy lại khóa dựa trên mật khẩu. Nếu bạn sử dụng mật khẩu, hãy sử dụng nó một cách chính xác.
Maarten Bodewes

5

Đối với AES / CBC / PKCS7 mã hóa / giải mã, chỉ cần sao chép và dán đoạn mã sau và thay thế SecretKeyIVvới riêng bạn.

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import android.util.Base64;


public class CryptoHandler {

    String SecretKey = "xxxxxxxxxxxxxxxxxxxx";
    String IV = "xxxxxxxxxxxxxxxx";

    private static CryptoHandler instance = null;

    public static CryptoHandler getInstance() {

        if (instance == null) {
            instance = new CryptoHandler();
        }
        return instance;
    }

    public String encrypt(String message) throws NoSuchAlgorithmException,
            NoSuchPaddingException, IllegalBlockSizeException,
            BadPaddingException, InvalidKeyException,
            UnsupportedEncodingException, InvalidAlgorithmParameterException {

        byte[] srcBuff = message.getBytes("UTF8");
        //here using substring because AES takes only 16 or 24 or 32 byte of key 
        SecretKeySpec skeySpec = new 
        SecretKeySpec(SecretKey.substring(0,32).getBytes(), "AES");
        IvParameterSpec ivSpec = new 
        IvParameterSpec(IV.substring(0,16).getBytes());
        Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        ecipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
        byte[] dstBuff = ecipher.doFinal(srcBuff);
        String base64 = Base64.encodeToString(dstBuff, Base64.DEFAULT);
        return base64;
    }

    public String decrypt(String encrypted) throws NoSuchAlgorithmException,
            NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException,
            BadPaddingException, UnsupportedEncodingException {

        SecretKeySpec skeySpec = new 
        SecretKeySpec(SecretKey.substring(0,32).getBytes(), "AES");
        IvParameterSpec ivSpec = new 
        IvParameterSpec(IV.substring(0,16).getBytes());
        Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        ecipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
        byte[] raw = Base64.decode(encrypted, Base64.DEFAULT);
        byte[] originalBytes = ecipher.doFinal(raw);
        String original = new String(originalBytes, "UTF8");
        return original;
    }
}

Bạn có thêm chức năng có thể mã hóa tệp không? Loại trả lại sẽ là byte []
Paritosh

1
Bạn chỉ cần gọi các hàm này bằng tên lớp. ví dụ. CryptoHandler.encrypt ("STRING CỦA BẠN mà bạn muốn mã hóa") và giống với cái này, bạn cũng có thể gọi decrypt (). Và cả hai hàm đều trả về Chuỗi.
Sujeet Kumar Gupta

2
Cảnh báo Một khóa không phải là một chuỗi, một khóa và IV không được "chọn" bởi người dùng. IV phải không thể đoán trước (không thể phân biệt được với ngẫu nhiên) đối với một đối thủ để CBC được bảo mật. Một nỗ lực không thành công khác, bạn trên # 10 không nhận được mật mã và vẫn sẵn sàng cung cấp "ví dụ". Đây cũng là một câu trả lời chỉ có mã, nó không giải thích loại bảo mật mà nó cung cấp.
Maarten Bodewes

2

API đơn giản để thực hiện mã hóa AES trên Android. Đây là bản sao của Android với thư viện AESCrypt Ruby và Obj-C (có cùng mặc định):

https://github.com/scottyab/AESCrypt-Android


7
Bạn có thể mở rộng một chút cách sử dụng thư viện này để giải quyết vấn đề không? Chỉ sao chép mô tả GitHub và thêm liên kết vào đó không phải là tất cả đều hữu ích và câu trả lời của bạn có thể tốt hơn nhiều với một số giải thích.
JonasCz - Phục hồi Monica

1

Đây là đoạn mã đơn giản hoạt động cho Mã hóa và Giải mã AES.

import android.util.Base64;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
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 AESEncryptionClass {

    private static String INIT_VECTOR_PARAM = "#####";
    private static String PASSWORD = "#####";
    private static String SALT_KEY = "#####";

    private static SecretKeySpec generateAESKey() throws NoSuchAlgorithmException, InvalidKeySpecException {

        // Prepare password and salt key.
        char[] password = new String(Base64.decode(PASSWORD, Base64.DEFAULT)).toCharArray();
        byte[] salt = new String(Base64.decode(SALT_KEY, Base64.DEFAULT)).getBytes(StandardCharsets.UTF_8);

        // Create object of  [Password Based Encryption Key Specification] with required iteration count and key length.
        KeySpec spec = new PBEKeySpec(password, salt, 64, 256);

        // Now create AES Key using required hashing algorithm.
        SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec);

        // Get encoded bytes of secret key.
        byte[] bytesSecretKey = key.getEncoded();

        // Create specification for AES Key.
        SecretKeySpec secretKeySpec = new SecretKeySpec(bytesSecretKey, "AES");
        return secretKeySpec;
    }

    /**
     * Call this method to encrypt the readable plain text and get Base64 of encrypted bytes.
     */
    public static String encryptMessage(String message) throws BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException {

        byte[] initVectorParamBytes = new String(Base64.decode(INIT_VECTOR_PARAM, Base64.DEFAULT)).getBytes(StandardCharsets.UTF_8);

        Cipher encryptionCipherBlock = Cipher.getInstance("AES/CBC/PKCS5Padding");
        encryptionCipherBlock.init(Cipher.ENCRYPT_MODE, generateAESKey(), new IvParameterSpec(initVectorParamBytes));

        byte[] messageBytes = message.getBytes();
        byte[] cipherTextBytes = encryptionCipherBlock.doFinal(messageBytes);
        String encryptedText = Base64.encodeToString(cipherTextBytes, Base64.DEFAULT);
        return encryptedText;
    }

    /**
     * Call this method to decrypt the Base64 of encrypted message and get readable plain text.
     */
    public static String decryptMessage(String base64Cipher) throws BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException {

        byte[] initVectorParamBytes = new String(Base64.decode(INIT_VECTOR_PARAM, Base64.DEFAULT)).getBytes(StandardCharsets.UTF_8);

        Cipher decryptionCipherBlock = Cipher.getInstance("AES/CBC/PKCS5Padding");
        decryptionCipherBlock.init(Cipher.DECRYPT_MODE, generateAESKey(), new IvParameterSpec(initVectorParamBytes));

        byte[] cipherBytes = Base64.decode(base64Cipher, Base64.DEFAULT);
        byte[] messageBytes = decryptionCipherBlock.doFinal(cipherBytes);
        String plainText = new String(messageBytes);
        return plainText;
    }
}

Bây giờ , hãy gọi encryptMessage()hoặc decryptMessage()cho mong muốnAES Hoạt động với các thông số cần thiết.

Ngoài ra , hãy xử lý các ngoại lệ trong quá trình AEShoạt động.

Hy vọng nó đã giúp ...


1
Muối tĩnh và IV không an toàn.
Maarten Bodewes

0

Để thêm lâu đài bouncy vào dự án Android: https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16/1.45

Thêm dòng này vào Hoạt động chính của bạn:

static {
    Security.addProvider(new BouncyCastleProvider());
}

public class AESHelper {

    private static final String TAG = "AESHelper";

    public static byte[] encrypt(byte[] data, String initVector, String key) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            Cipher c = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            SecretKeySpec k = new SecretKeySpec(Base64.decode(key, Base64.DEFAULT), "AES");
            c.init(Cipher.ENCRYPT_MODE, k, iv);
            return c.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static byte[] decrypt(byte[] data, String initVector, String key) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            Cipher c = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            SecretKeySpec k = new SecretKeySpec(Base64.decode(key, Base64.DEFAULT), "AES");
            c.init(Cipher.DECRYPT_MODE, k, iv);
            return c.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static String keyGenerator() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(192);

        return Base64.encodeToString(keyGenerator.generateKey().getEncoded(),
                Base64.DEFAULT);
    }
}


Tôi không nghĩ bạn cần Bouncy cho điều này; nó sẽ chỉ đảm bảo rằng bạn không thể sử dụng tính năng tăng tốc phần cứng và giảm hiệu suất cho các tệp lớn (chẳng hạn như hình ảnh). Mã hóa khóa trong cơ sở 64 là một ý tưởng tồi; lưu trữ nó trong một cửa hàng quan trọng là tốt hơn nhiều.
Maarten Bodewes

0

Hãy thử với đoạn mã dưới đây, nó có hiệu quả với tôi.

public static String decrypt(String encrypted) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
    byte[] key = your Key in byte array;
    byte[] input = salt in byte array;

    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(input);
    Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    ecipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);

    byte[] raw = Base64.decode(encrypted, Base64.DEFAULT);
    byte[] originalBytes = ecipher.doFinal(raw);

    String original = new String(originalBytes, "UTF8");
    return original;
}

1
Mã tiền điện tử không nên chỉ hoạt động, nó phải an toàn. Bạn có thể chỉ ra những gì loại bảo mật mã của bạn cung cấp (hoặc trong trường hợp này, không cung cấp?)
Maarten Bodewes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.