Kotlin에서 AES 사용하기


코틀린에서 AES 사용하는법 찾아서 해보고 여기 정리 해둠.

fun hashSHA256(msg: String): ByteArray {
    val hash: ByteArray
    try {
        val md = MessageDigest.getInstance("SHA-256")
        md.update(msg.toByteArray())
        hash = md.digest()
    } catch (e: CloneNotSupportedException) {
        throw DigestException("couldn't make digest of partial content")
    }
    return hash
}

hashSHA256 함수는 문자열을 넣으면 32바이트 배열을 리턴해줌.
SHA256 해시를 돌리는것인데 이유는 들어가는 비밀번호의 길이가 16바이트면 AES128, 24바이트면 AES192, 32바이트면 AES256으로 처리되기 때문임.

인터넷 검색해보니 AES 정리해놓은 일부 블로그에선 문자열 뒤에 값 넣어서 16바이트나 32비트를 맞추던데 그냥 해시함수 쓰면 간단하게 해결됨.
(암호를 디비에 저장할때 털리지 말라고 솔트랑 해시를 씀)

var text = "동해물과백두산이"
var password = "가나다라"
var iv = ByteArray(16)

val keySpec = SecretKeySpec(hashSHA256(password), "AES")

iv는 초기화 벡터라고 16바이트 배열인데 이 값에 따라 암호화 결과 값이 달라짐.
외부에 노출되도 (가급적 안되는게 좋겠지만) 암호화 된거 깨는데 큰 영향을 주지 않는다는 글을 봤음. 일단 예제는 0으로 채워진 16바이트로 함.
비밀번호(“가나다라”)를 hashSHA256 함수를 통해 32바이트 바이트배열로 변환해 넣어서 줌.

//암호화 하는 부분
val cipher_enc = Cipher.getInstance("AES/CBC/PKCS7Padding")
cipher_enc.init(Cipher.ENCRYPT_MODE, keySpec, IvParameterSpec(iv))
val byteEncryptedText = cipher_enc.doFinal(text.toByteArray())

“AES/CBC/PKCS7PAdding” 이것은 옵션인데 종류가 상당히 많은데 자세한것은 Link 를 참고하면 될듯 싶음 (안드로이드 버전에 따라 지원되는 암호화 옵션이 바뀜)
마지막줄에서 실제적으로 텍스트를 암호화한다.

//복호화 하는 부분
val cipher_dec = Cipher.getInstance("AES/CBC/PKCS7Padding")
cipher_dec.init(Cipher.DECRYPT_MODE, keySpec, IvParameterSpec(iv))
val byteDecryptedText = cipher_dec.doFinal(byteEncryptedText)

Log.d("linsoo","원본 : "+text)
Log.d("linsoo", "암호화 : "+ String(Base64.encode(byteEncryptedText, Base64.DEFAULT)))
Log.d("linsoo", "복호화 : "+ String(byteDecryptedText))

복호화 하는 부분도 큰 차이가 없는데 cipher.init 부분에서 DECRYPT_MODE로 바꿔주기만 하면 된다. 인코딩 할때 사용했던 키와 iv를 넣어주는데 각각 1바이트라도 틀리면 인코딩이 안되니 주의하길..

화면에 출력할때 암호화 된 값을 Base64로 인코딩 하는건 바이트 배열 그대로 출력하면 안나오는 값이 있어서 가시화 할때 좋음. 이렇게 하면 맨 위 스샷 처럼 작동하는것을 볼 수 있음.

아래는 전체 소스

var text = "동해물과백두산이"
var password = "가나다라"
var iv = ByteArray(16)

val keySpec = SecretKeySpec(hashSHA256(password), "AES")

//암호화 하는 부분
val cipher_enc = Cipher.getInstance("AES/CBC/PKCS7Padding")
cipher_enc.init(Cipher.ENCRYPT_MODE, keySpec, IvParameterSpec(iv))
val byteEncryptedText = cipher_enc.doFinal(text.toByteArray())

//복호화 하는 부분
val cipher_dec = Cipher.getInstance("AES/CBC/PKCS7Padding")
cipher_dec.init(Cipher.DECRYPT_MODE, keySpec, IvParameterSpec(iv))
val byteDecryptedText = cipher_dec.doFinal(byteEncryptedText)

Log.d("linsoo","원본 : "+text)
Log.d("linsoo", "암호화 : "+ String(Base64.encode(byteEncryptedText, Base64.DEFAULT)))
Log.d("linsoo", "복호화 : "+ String(byteDecryptedText))

댓글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다