Search

개인정보 암복호화 가이드

OPEN API 사용을 위한 개인정보 복호화 플로우

1.
RSA 키 쌍 생성
a.
토스쪽에 공개키 전달
b.
서로간의 방화벽 허용이 필요함
토스 오피스 IP
182.162.119.2
211.106.118.97
210.99.240.112
15.164.196.66
43.202.172.33
운영 서버 IP대역
117.52.3.80 ~ 87
211.115.96.80 ~ 87
2.
API를 통해 encryptedKey, iv 그리고 암호화된 개인정보를 받음
3.
encryptedKey를 1에서 생성한 키 쌍의 개인키로 RSA복호화를 진행하여 AES Key를 생성
4.
3에서 만든 AES key와 iv 값으로 AES 복호화를 진행해주시면 됩니다

AES 암복호화 샘플코드

import java.util.* import javax.crypto.Cipher import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.SecretKeySpec class AesEncryptManager { companion object { const val GCM_TAG_BYTE_LENGTH = 16 } fun encryptGcm(target: ByteArray, secretKey: ByteArray, iv: ByteArray): String { val cipher = Cipher.getInstance("AES/GCM/NoPadding") val nonceSpec = GCMParameterSpec(GCM_TAG_BYTE_LENGTH * Byte.SIZE_BITS, iv) cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(secretKey, "AES"), nonceSpec) val ciphertext = cipher.doFinal(target) return Base64.getEncoder().encodeToString(ciphertext) } fun decryptGcm(target: String, secretKey: ByteArray, iv: ByteArray): ByteArray { val encrypted = Base64.getDecoder().decode(target) val cipher = Cipher.getInstance("AES/GCM/NoPadding") val nonceSpec = GCMParameterSpec(GCM_TAG_BYTE_LENGTH * Byte.SIZE_BITS, iv) cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(secretKey, "AES"), nonceSpec) return cipher.doFinal(encrypted) } } fun main() { val aesEncryptManager = AesEncryptManager() val secretKey = "l6JmtDcgDU3igWLgRF4QdVbjaleD9IMMphkfd6Egzb4=" // Base64.getEncoder().encodeToString(SecureRandom().nextBytes(ByteArray(32))) val iv = "A230BGRSpFiqqt6B" // Base64.getEncoder().encodeToString(SecureRandom().nextBytes(ByteArray(12))) val target = "김토스" val secretBytes = Base64.getDecoder().decode(secretKey) val ivBytes = Base64.getDecoder().decode(iv) val gcmEncrypted = aesEncryptManager.encryptGcm(target.toByteArray(), secretBytes, ivBytes) val gcmDecrypted = aesEncryptManager.decryptGcm(gcmEncrypted, secretBytes, ivBytes) println("GCM Encrypted: $gcmEncrypted") println("GCM Decrypted: ${String(gcmDecrypted, Charsets.UTF_8)}") }
Kotlin
복사

RSA 암복호화 샘플코드

OAEP 해시: SHA-256
MGF1 해시: SHA-1
fun encryptWithRSA(plain: ByteArray, publicKey: PublicKey): ByteArray { val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding") cipher.init(Cipher.ENCRYPT_MODE, publicKey) return cipher.doFinal(plain) } fun decryptWithRSA(encryptedTarget: String): ByteArray { val privateKeyStr = Base64.getDecoder().decode("privateKey를 여기에 입력하세요") val keyFactory = KeyFactory.getInstance("RSA") val privateKey = keyFactory.generatePrivate(PKCS8EncodedKeySpec(privateKeyStr)) val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding") cipher.init(Cipher.DECRYPT_MODE, privateKey) val byteEncrypted: ByteArray = Base64.getDecoder().decode(encryptedTarget) return cipher.doFinal(byteEncrypted) }
Kotlin
복사

전체 샘플코드

import java.security.KeyFactory import java.security.PublicKey import java.security.SecureRandom import java.security.spec.PKCS8EncodedKeySpec import java.security.spec.X509EncodedKeySpec import java.util.* import javax.crypto.Cipher import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.SecretKeySpec /** * 외부 제휴사에게 제공할 샘플 코드 */ class SampleEncryptManager { companion object { private const val GCM_TAG_BYTE_LENGTH = 16 } fun generateAesKey(): ByteArray { val key = ByteArray(32) SecureRandom().nextBytes(key) return key } fun generateIv(): ByteArray { val iv = ByteArray(12) SecureRandom().nextBytes(iv) return iv } fun convertEncodedToPublicKey(encoded: ByteArray, algorithm: String): PublicKey { val keyFactory = KeyFactory.getInstance(algorithm) return keyFactory.generatePublic(X509EncodedKeySpec(encoded)) } fun encryptGcm(target: ByteArray, secretKey: ByteArray, iv: ByteArray): String { val cipher = Cipher.getInstance("AES/GCM/NoPadding") val nonceSpec = GCMParameterSpec(GCM_TAG_BYTE_LENGTH * Byte.SIZE_BITS, iv) cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(secretKey, "AES"), nonceSpec) val ciphertext = cipher.doFinal(target) return Base64.getEncoder().encodeToString(ciphertext) } fun decryptGcm(target: String, secretKey: ByteArray, iv: ByteArray): ByteArray { val encrypted = Base64.getDecoder().decode(target) val cipher = Cipher.getInstance("AES/GCM/NoPadding") val nonceSpec = GCMParameterSpec(GCM_TAG_BYTE_LENGTH * Byte.SIZE_BITS, iv) cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(secretKey, "AES"), nonceSpec) return cipher.doFinal(encrypted) } fun encryptWithRSA(plain: ByteArray, publicKey: PublicKey): ByteArray { val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding") cipher.init(Cipher.ENCRYPT_MODE, publicKey) return cipher.doFinal(plain) } fun decryptWithRSA(encryptedTarget: String): ByteArray { val privateKeyBytes = Base64.getDecoder().decode("privateKey를 여기에 입력하세요") val keyFactory = KeyFactory.getInstance("RSA") val privateKey = keyFactory.generatePrivate(PKCS8EncodedKeySpec(privateKeyBytes)) val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding") cipher.init(Cipher.DECRYPT_MODE, privateKey) val byteEncrypted: ByteArray = Base64.getDecoder().decode(encryptedTarget) return cipher.doFinal(byteEncrypted) } } fun main() { val encryptManager = SampleEncryptManager() // 1. 데이터 암호화 // AES 키 생성 예) l6JmtDcgDU3igWLgRF4QdVbjaleD9IMMphkfd6Egzb4= val aesKeyBytes: ByteArray = encryptManager.generateAesKey() val base64encodedAesKey: String = Base64.getEncoder().encodeToString(aesKeyBytes) println("AES key: $base64encodedAesKey") // IV 생성 예) A230BGRSpFiqqt6B val ivBytes: ByteArray = encryptManager.generateIv() val base64encodedIv: String = Base64.getEncoder().encodeToString(ivBytes) println("IV: $base64encodedIv") val name = "김토스" // AES-GCM 암호화 (target을 암호화) val gcmAesEncryptedName = encryptManager.encryptGcm(name.toByteArray(), aesKeyBytes, ivBytes) println("GCM AES Encrypted name: $gcmAesEncryptedName") // RSA 암호화 (AES 키 암호화) val publicKeyBytes = Base64.getDecoder().decode("publicKey를 여기에 입력하세요") val publicKey = encryptManager.convertEncodedToPublicKey(publicKeyBytes, "RSA") val rsaEncryptedKey = encryptManager.encryptWithRSA(aesKeyBytes, publicKey) // 2. API 응답 val encryptedName = gcmAesEncryptedName val encryptedKey: String = Base64.getEncoder().encodeToString(rsaEncryptedKey) val iv: String = Base64.getEncoder().encodeToString(ivBytes) println("Response - encryptedName: $encryptedName") println("Response - encryptedKey: $encryptedKey") println("Response - iv: $iv") // 3. 데이터 복호화 // RSA 복호화 (AES 키 복호화) val rsaDecryptedKey = encryptManager.decryptWithRSA(encryptedKey) val decodedIv = Base64.getDecoder().decode(iv) val gcmDecrypted = encryptManager.decryptGcm(encryptedName, rsaDecryptedKey, decodedIv) println("GCM AES Decrypted name: ${String(gcmDecrypted, Charsets.UTF_8)}") }
Kotlin
복사