투케이2K

278. (AndroidStudio/android/java) [재등록] aes 암호화 파생 인코딩 , 디코딩 수행 실시 - secretkey , iv , salt 본문

Android

278. (AndroidStudio/android/java) [재등록] aes 암호화 파생 인코딩 , 디코딩 수행 실시 - secretkey , iv , salt

투케이2K 2022. 3. 14. 08:03
반응형

[개발 환경 설정]

개발 툴 : AndroidStudio

개발 언어 : java

 

[소스 코드]

 

package com.test.app;

import android.util.Base64;
import android.util.Log;

import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;
import java.util.Arrays;

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 C_AES256 {


    /**
     * TODO [클래스 설명]
     * // -----------------------------------------
     * 1. AES256 암호화 수행 파생 클래스
     * 2. 추가하는 값 KEY, IV, SALT 값
     * 3. CBC : 블록 암호화 운영 모드 중 보안 성이 제일 높은 암호화 방법으로 가장 많이 사용 (IV 사용)
     * 4. PKCS 5 : 8 바이트 패딩 (데이터 길이가 모자라다면 8 바이트까지 마지막 값 기준 채우고, 8 바이트 이상인 경우 뒤에 8바이트 패딩 추가)
     * 5. PKCS 7 : 16 바이트 패딩 (데이터 길이가 모자라다면 16 바이트까지 마지막 값 기준 채우고, 16 바이트 이상인 경우 뒤에 8바이트 패딩 추가)
     * 6. 참고 사이트 (aos) : https://www.tabnine.com/code/java/methods/javax.crypto.spec.PBEKeySpec/%3Cinit%3E
     * 7. 참고 사이트 (ios) : https://gist.github.com/hfossli/7165dc023a10046e2322b0ce74c596f8
     * // -----------------------------------------
     * */



    /** TODO [결과 출력 예시]
     W///===========//: ================================================
     I/: [C_AES256 >> encrypt() :: AES 암호화 인코딩 수행 실시]
     --------------------
     [secretKey :: 0123456789abcdef0123456789abcdef]
     --------------------
     [iv [string] :: 0123456789abcdef0123456789abcdef]
     [iv [byte] :: [1, 35, 69, 103, -119, -85, -51, -17, 1, 35, 69, 103, -119, -85, -51, -17]]
     I/: [iv [hex] :: 01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF ]
     --------------------
     [salt [string] :: 0123456789abcdef0123456789abcdef]
     [salt [byte] :: [1, 35, 69, 103, -119, -85, -51, -17, 1, 35, 69, 103, -119, -85, -51, -17]]
     I/: [salt [hex] :: 01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF ]
     --------------------
     [keyLength :: 32]
     --------------------
     [iterationCount :: 1000]
     --------------------
     [원본 :: hello]
     [인코딩 :: 0yHy16m2dy5OpZH2+NX/4w==
     ]
     W///===========//: ================================================

     W///===========//: ================================================
     I/: [C_AES256 >> decrypt() :: AES 암호화 디코딩 수행 실시]
     --------------------
     [secretKey :: 0123456789abcdef0123456789abcdef]
     --------------------
     [iv [string] :: 0123456789abcdef0123456789abcdef]
     [iv [hex] :: [1, 35, 69, 103, -119, -85, -51, -17, 1, 35, 69, 103, -119, -85, -51, -17]]
     I/: [iv [hex] :: 01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF ]
     --------------------
     [salt [string] :: 0123456789abcdef0123456789abcdef]
     [salt [hex] :: [1, 35, 69, 103, -119, -85, -51, -17, 1, 35, 69, 103, -119, -85, -51, -17]]
     I/: [salt [hex] :: 01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF ]
     --------------------
     [keyLength :: 32]
     --------------------
     [iterationCount :: 1000]
     --------------------
     [원본 :: 0yHy16m2dy5OpZH2+NX/4w==
     ]
     [디코딩 :: hello]
     W///===========//: ================================================
     */



    // TODO [전역 변수 선언 부분]
    public static final String secretKey = "0123456789abcdef0123456789abcdef";  // [32 바이트]

    //public static final String ivKey = "0123456789abcdef";
    public static final String ivKey = "0123456789abcdef0123456789abcdef";  // [32 바이트]
    //public static final byte[] iv = ivKey.getBytes(); // [16 바이트]
    public static final byte[] iv = C_Util.HexUtil_To_ByteArray(ivKey); // [16 바이트]

    public static final String saltKey = "0123456789abcdef0123456789abcdef";
    //public static final byte[] salt = saltKey.getBytes(); // [random byte]
    public static final byte[] salt = C_Util.HexUtil_To_ByteArray(saltKey); // [random byte]

    public static final String padding = "AES/CBC/PKCS7Padding";  // [알고리즘]

    public static final int iterationCount = 1000;
    public static final int keyLength = 256; // [32 length]

    public static final String algo = "PBKDF2WithHmacSHA1";  // [알고리즘]
    public static final String secretKeySpecType = "AES";  // [타입]



    // TODO [AES256 base64 데이터 인코딩 수행]
    public static String encrypt(String strToEncrypt) {
        String returnData = "";
        try {
            // [iv 지정 : iv hex]
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            // [알고리즘 지정]
            SecretKeyFactory factory = SecretKeyFactory.getInstance(algo);

            // [KeySpec : salt hex]
            KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, iterationCount, keyLength);
            SecretKey tmp = factory.generateSecret(spec);

            // [SecretKeySpec : 인코딩, 디코딩 수행에서 AES 지정]
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), secretKeySpecType); // [인코딩, 디코딩 수행에서 AES 지정]

            // [Cipher]
            Cipher cipher = Cipher.getInstance(padding); // [인코딩, 디코딩 수행에서 필요한 패딩 지정]
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec); // [KeySpec + iv]
            returnData = Base64.encodeToString(cipher.doFinal(strToEncrypt.getBytes()), 0); // [base64 결과 반환 데이터]
        } catch (Exception e) {
            //e.printStackTrace();
        }
        Log.i("---","---");
        Log.w("//===========//","================================================");
        Log.i("","\n"+"[C_AES256 >> encrypt() :: AES 암호화 인코딩 수행 실시]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[secretKey :: "+String.valueOf(secretKey)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[iv [string] :: "+String.valueOf(ivKey)+"]");
        Log.i("","\n"+"[iv [byte] :: "+Arrays.toString(iv)+"]");
        Log.i("","\n"+"[iv [hex] :: "+C_Util.convert_ByteArray_To_HexString(iv)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[salt [string] :: "+String.valueOf(saltKey)+"]");
        Log.i("","\n"+"[salt [byte] :: "+Arrays.toString(salt)+"]");
        Log.i("","\n"+"[salt [hex] :: "+C_Util.convert_ByteArray_To_HexString(salt)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[keyLength :: "+String.valueOf(keyLength/8)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[iterationCount :: "+String.valueOf(iterationCount)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[원본 :: "+String.valueOf(strToEncrypt)+"]");
        Log.i("","\n"+"[인코딩 :: "+String.valueOf(returnData)+"]");
        Log.w("//===========//","================================================");
        Log.i("---","---");
        return returnData;
    }



    // TODO [AES256 base64 데이터 디코딩 수행]
    public static String decrypt(String strToDecrypt) {
        String returnData = "";
        try {
            // [iv 지정 : iv hex]
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            // [알고리즘 지정]
            SecretKeyFactory factory = SecretKeyFactory.getInstance(algo);

            // [KeySpec : salt hex]
            KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, iterationCount, keyLength);
            SecretKey tmp = factory.generateSecret(spec);

            // [SecretKeySpec : 인코딩, 디코딩 수행에서 AES 지정]
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), secretKeySpecType); // [인코딩, 디코딩 수행에서 AES 지정]

            // [Cipher]
            Cipher cipher = Cipher.getInstance(padding); // [인코딩, 디코딩 수행에서 필요한 패딩 지정]
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec); // [KeySpec + iv]
            returnData = new String(cipher.doFinal(Base64.decode(strToDecrypt, 0))); // [원본 데이터 반환]
        } catch (Exception e) {
            //e.printStackTrace();
        }
        Log.i("---","---");
        Log.w("//===========//","================================================");
        Log.i("","\n"+"[C_AES256 >> decrypt() :: AES 암호화 디코딩 수행 실시]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[secretKey :: "+String.valueOf(secretKey)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[iv [string] :: "+String.valueOf(ivKey)+"]");
        Log.i("","\n"+"[iv [hex] :: "+Arrays.toString(iv)+"]");
        Log.i("","\n"+"[iv [hex] :: "+C_Util.convert_ByteArray_To_HexString(iv)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[salt [string] :: "+String.valueOf(saltKey)+"]");
        Log.i("","\n"+"[salt [hex] :: "+Arrays.toString(salt)+"]");
        Log.i("","\n"+"[salt [hex] :: "+C_Util.convert_ByteArray_To_HexString(salt)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[keyLength :: "+String.valueOf(keyLength/8)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[iterationCount :: "+String.valueOf(iterationCount)+"]");
        Log.i("","\n"+"--------------------");
        Log.i("","\n"+"[원본 :: "+String.valueOf(strToDecrypt)+"]");
        Log.i("","\n"+"[디코딩 :: "+String.valueOf(returnData)+"]");
        Log.w("//===========//","================================================");
        Log.i("---","---");
        return returnData;
    }

} // TODO [클래스 종료]

 

반응형
Comments