AES를 사용한 Android 암호화 / 복호화 [닫힘]


105

Android에서 AES 를 사용하여 이미지 및 기타 파일 을 암호화하고 해독 하는 방법에 대한 좋은 예가 있습니까?


7
Android의 암호화는 다른 Java SE 플랫폼과 근본적으로 다르지 않습니다. 그리고 아래의 모든 답변은 안전하지 않으므로 암호화 예제를 구현하거나 빌리기 전에 암호화를 이해해야합니다.
Maarten Bodewes 2014-06-10

4
github.com/facebook/conceal 시도해야합니다 .
Nhat Dinh

답변:


131

경고 :이 답변에는 안전하지 않으므로 사용해서는 안되는 코드가 포함되어 있습니다 (키 파생에 SHA1PRNG 사용 및 ECB 모드에서 AES 사용).

대신 (2016 년 기준), 키 유도에 PBKDF2WithHmacSHA1을 사용하고 CBC 또는 GCM 모드에서 AES를 사용합니다 (GCM은 개인 정보 보호와 무결성을 모두 제공).

다음과 같은 기능을 사용할 수 있습니다.

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

그리고 다음과 같이 호출하십시오.

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

이것은 작동합니다. 지금 프로젝트에서 비슷한 코드를 사용합니다.


9
이건 나를 위해 작동하지 않습니다. 동일한 암호를 해독하는 동안 Badpadding 예외가 발생합니다.
Sanat Pandey 2011

34
경고이 코드는 키 파생을 위해 Android 스 니펫에서 알려진 잘못된 코드를 사용하고 있습니다. 데이터를 잃어 버리고 싶지 않으면 사용하지 마십시오. 시드 된 RNG는좋은 KDF (Key Derivation Function)가 아닙니다 .
Maarten Bodewes 2014-06-09


35
경고이 코드는 대부분의 플랫폼에서 ECB 모드 암호화로 기본 설정 될 수 있습니다. ECB 모드 암호화를 사용하는 것은 사진은 물론 대부분의 데이터에 안전하지 않습니다. 펭귄을 찾아라!
Maarten Bodewes 2014-06-10

10
@Maarten Bodewes 많은 게시물 아래에서 모든 곳에서 경고를 봅니다. 대신 좋은 솔루션을 제공해 주시겠습니까?
Yar

16

Nacho.L에서 언급했듯이 PBKDF2WithHmacSHA1 파생은 더 안전하기 때문에 사용됩니다.

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

}

3
사실이 파생이 훨씬 낫습니다. 그러나 이제 정적 IV, 정적 솔트 및 너무 낮은 반복 횟수를 사용하고 있습니다. 따라서 경고없이 결과는 여전히 안전하지 않습니다. 암호화는 바로 잡기의 고통입니다 ...
Maarten Bodewes

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
위 코드는 Android 4.2에서 BadPaddingException을 발생
시킵니다.

1
@BrijeshThakur- 이것을
t0mm13b

12
경고이 코드는 키 파생을 위해 Android 스 니펫의 알려진 잘못된 코드를 사용하고 있습니다. 데이터를 잃어 버리고 싶지 않으면 사용하지 마십시오. 시드 된 RNG는좋은 KDF (Key Derivation Function)가 아닙니다 .
Maarten Bodewes 2014-06-09

3
자세한 정보는 여기
Maarten Bodewes 2014-06-09

9
경고이 코드는 대부분의 플랫폼에서 ECB 모드 암호화로 기본 설정 될 수 있습니다. ECB 모드 암호화를 사용하는 것은 사진은 물론 대부분의 데이터에 안전하지 않습니다. 펭귄을 찾아라!
Maarten Bodewes 2014-06-10

9

이전 질문이지만 4.2 이전 및 이후 Android를 지원하는 답변을 업그레이드하고 Android 개발자 블로그 에 따라 모든 최근 변경 사항을 고려합니다.

또한 github repo 에 작업 예제를 남깁니다 .

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

Apache Commons Codec 라이브러리를 사용하는 대신 android.util.Base64.encode(bytes, Base64.DEFAULT)및 사용하는 데 단점이 android.util.Base64.decode(decryptedData, Base64.DEFAULT)있습니까?
ban-geoengineering

2
경고이 코드는 키 파생을 위해 Android 스 니펫의 알려진 잘못된 코드를 사용하고 있습니다. 데이터를 잃어 버리고 싶지 않으면 사용하지 마십시오. 시드 된 RNG는 좋은 KDF (Key Derivation Function)가 아닙니다. (한숨).
Maarten Bodewes

1
@MaartenBodewes 어떤 변경을해야합니까?
Ricardo

7

텍스트 파일을 암호화하는 경우 다음 테스트 / 샘플이 유용 할 수 있습니다. 다음을 수행합니다.

  1. 바이트 스트림 생성,
  2. AES 암호화를 사용하여
  3. 텍스트 처리로 다음 랩핑
  4. 마지막으로 버퍼링

    // 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
경고이 코드는 기본 문자 디코딩을 사용하는 키 파생 메커니즘을 사용하고 있습니다. 데이터를 해독하는 데 문제가있는 경우가 아니면 사용하지 마십시오.
Maarten Bodewes 2014-06-09

3
@owlstead, 좋은 관찰, 당신이 수정을 제안했다면 좋았을 것입니다. 위의 예는 이제 getKey ()에서 문자 인코딩을 지정하도록 업데이트되었습니다. 추가 수정을 환영합니다 ...
SoloPilot

9
죄송합니다 SecureRandom. 키 파생에 사용 되었기 때문에 주로 여기에서 답변을 태 웠습니다 . 암호를 인스턴스화하는 방법을 알고 싶다면 여기에서 ericksons의 답변을 확인 하십시오 . 정적 IV (동일한 키에 대해)를 사용하지 말고 암호-> 키 변환에 PBKDF2를 사용하십시오. 인증되지 않은 암호는 전송 프로토콜에서 사용되지 않는 경우에만 기밀성을 제공합니다. 당신이 도움을 원한다면, 당신은 :) 너무 다른 답변을 구울 (거기에 내 의견을 투표를) 할 수 있습니다
마틴 Bodewes에게

@MaartenBodewes 당신은 많은 대답을 "불태 웠지만"대답을 제안하지 않습니다. 정답이있는 경우 여기에 작성하지 않는 이유는 무엇입니까?
Dika

@Dika 나는 위에서 대답을 지적했다고 생각합니다. 나는 암호화와 암호화 모두에 대해 가장 많은 답변을 게시하는 사람이 매우 큰 마진 을 가지고 있음을 명심하십시오 . 또한 특정 사용 사례에 대한 코드를 직접 작성하기보다 사람들이 단순히 코드를 복사하도록 유도하는 일반 래퍼 라이브러리에 반대한다는 점을 명심하십시오. Java crypto API는 다소 번거롭지 만 다소 잘 생각됩니다. 그것을 사용하십시오! 이미지 암호화에는 특별한 것이 없습니다. 기본 파일 암호화입니다.
Maarten Bodewes

5

안드로이드에서 AES 암호화 / 복호화

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

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

암호화 기능

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

해독 기능

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

C #에서 AES 암호화 / 복호화

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

            Console.ReadKey();
        }

암호화 기능

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

해독 기능

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

MD5 생성

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

1
MD5는 암호 해시 또는 암호 기반 키 파생 기능이 아닙니다. 암호를 사용하는 경우 올바르게 사용하십시오.
Maarten Bodewes

5

AES의 경우 / CBC / PKCS7 암호화 / 암호 해독, 그냥 다음 코드를 복사하여 붙여 교체 SecretKeyIV자신과 함께.

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

파일을 인코딩 할 수있는 기능을 추가 하시겠습니까? 반환 유형은 byte []입니다.
Paritosh

1
이러한 함수를 클래스 이름으로 호출하면됩니다. 예. CryptoHandler.encrypt ( "암호화하려는 당신의 문자열") 그리고 이것과 동일하게 decrypt ()를 호출 할 수 있습니다. 그리고 두 함수 모두 문자열을 반환합니다.
Sujeet Kumar Gupta

2
경고 키는 문자열이 아니며 키와 IV는 사용자가 "선택"해서는 안됩니다. CBC가 보안을 유지하려면 IV가 적에게 예측할 수 없어야합니다 (무작위에서 알아볼 수 없음). 또 다른 실패한 시도, 당신은 암호화를 얻지 못해 # 10을 넘었고 여전히 "예"를 제공 할 의향이 있습니다. 이것은 코드 전용 답변이며 어떤 종류의 보안을 제공하는지 설명하지 않습니다.
Maarten Bodewes

2

Android에서 AES 암호화를 수행하는 간단한 API입니다. 이것은 AESCrypt 라이브러리 Ruby 및 Obj-C (동일한 기본값 사용)에 대응하는 Android입니다.

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


7
이 라이브러리를 사용하여 문제를 해결하는 방법을 조금 확장 할 수 있습니까? GitHub 설명을 복사하고 여기에 링크를 추가하는 것은 그다지 도움이되지 않으며 몇 가지 설명이 있으면 답변이 훨씬 더 나을 수 있습니다.
JonasCz-Monica 복원

1

다음은 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;
    }
}

이제 필요한 매개 변수를 사용하여 encryptMessage()또는 decryptMessage()원하는 AES작업을 호출 합니다.

또한AES 작업 중에 예외를 처리하십시오 .

도움이 되었기를 바랍니다 ...


1
정적 솔트와 IV는 안전하지 않습니다.
Maarten Bodewes

0

bouncy castle을 Android 프로젝트에 추가하려면 : https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16/1.45

주요 활동에 다음 줄을 추가하십시오.

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


나는 당신이 이것을 위해 Bouncy가 필요하다고 생각하지 않습니다. 하드웨어 가속을 사용할 수 없는지 확인하고 대용량 파일 (예 : 이미지)의 성능을 저하시킬뿐입니다. Base 64로 키를 인코딩하는 것은 좋지 않습니다. 키 저장소에 저장하는 것이 훨씬 좋습니다.
Maarten Bodewes

0

아래 코드로 시도해보십시오.

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
암호화 코드는 작동 할뿐만 아니라 안전해야합니다. 코드가 어떤 종류의 보안을 제공하는지 표시 할 수 있습니까 (또는이 경우에는 제공하지 않습니까?)
Maarten Bodewes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.