Kotlin에서 AES 사용하기

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
}
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 }
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비트를 맞추던데 그냥 해시함수 쓰면 간단하게 해결됨.
(암호를 디비에 저장할때 털리지 말라고 솔트랑 해시를 씀)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
var text = "동해물과백두산이"
var password = "가나다라"
var iv = ByteArray(16)
val keySpec = SecretKeySpec(hashSHA256(password), "AES")
var text = "동해물과백두산이" var password = "가나다라" var iv = ByteArray(16) val keySpec = SecretKeySpec(hashSHA256(password), "AES")
var text = "동해물과백두산이"
var password = "가나다라"
var iv = ByteArray(16)

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//암호화 하는 부분
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_enc = Cipher.getInstance("AES/CBC/PKCS7Padding") cipher_enc.init(Cipher.ENCRYPT_MODE, keySpec, IvParameterSpec(iv)) val byteEncryptedText = cipher_enc.doFinal(text.toByteArray())
//암호화 하는 부분
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 를 참고하면 될듯 싶음 (안드로이드 버전에 따라 지원되는 암호화 옵션이 바뀜)
마지막줄에서 실제적으로 텍스트를 암호화한다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//복호화 하는 부분
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))
//복호화 하는 부분 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))
//복호화 하는 부분
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로 인코딩 하는건 바이트 배열 그대로 출력하면 안나오는 값이 있어서 가시화 할때 좋음. 이렇게 하면 맨 위 스샷 처럼 작동하는것을 볼 수 있음.

아래는 전체 소스

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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))
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))
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))

Comments

답글 남기기

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