Created
June 15, 2021 09:53
-
-
Save chimerast/e0608f31f633bb1a8ed9867c21a79f87 to your computer and use it in GitHub Desktop.
KotlinでPEM形式の公開鍵暗号ペアファイルを扱う
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
このコードはKotlinでPEM形式のRSAおよびEC公開鍵暗号を利用したサンプルプログラムです。 | |
**警告**: 文字列になっている公開暗号鍵ペアは絶対にそのまま使用しないこと。 | |
opensslコマンドを打って必ず自分で生成してください。 | |
実行結果: | |
[RSA/ECB/PKCS1Padding] matched: true, original: Hello world!, decrypted: Hello world! | |
[SHA256withRSA] valid: true, original: Hello world! | |
[SHA256withECDSA] valid: true, original: Hello world! | |
*/ | |
import com.google.api.client.util.PemReader | |
import java.io.StringReader | |
import java.security.KeyFactory | |
import java.security.PrivateKey | |
import java.security.PublicKey | |
import java.security.Signature | |
import java.security.spec.PKCS8EncodedKeySpec | |
import java.security.spec.X509EncodedKeySpec | |
import javax.crypto.Cipher | |
fun main() { | |
CryptoSample.rsa("Hello world!") | |
CryptoSample.ecdsa("Hello world!") | |
} | |
object CryptoSample { | |
fun rsa(plaintext: String) { | |
/* | |
openssl genrsa -out key_rsa.pem 2048 | |
openssl rsa -in key_rsa.pem -pubout -out key_rsa.pub | |
openssl pkcs8 -in key_rsa.pem -topk8 -nocrypt -out key_rsa.key | |
*/ | |
val rsaPrivateKey = """ | |
-----BEGIN PRIVATE KEY----- | |
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDysAt+YD1mJksi | |
GW2z9EC1u4bYGvMOCK7lbmQNqEEInAwzxf1mBFlI3Gxz7twXvTjqF7EUaZg2Ue+f | |
VZ+WbX9ivvJpQrAEUwzbg1H83dso+VYeQNB04MQUpSrfRe1bfNyo6TzKSBr1merc | |
pKVZxayCNur1VmGsLpzUGaenbH5EcwlSd18sMsioA0opBHZg2WwKjfRwLbTAocr5 | |
qXR/9LgtmjbydxyVX8KSOl2cCLI/t+/xFP9WGl8iZdyQ5OjAmZEI6L/gLWe99RA0 | |
nIrPqT28I5y2ZhxTLYzVXOCRTWhibl4o4Bq0YjUk8JxMPET/o6uNxzcLpZgKOwIg | |
LyOWLTLDAgMBAAECggEBAIosIw8bujlregF7GtOHMESH9Tka9uE5nmIwHLUN46EE | |
P4pGooQv26m5HeJPz22QpVPak0585FWhBt3fwRHDW/CbqKa3ekGsCzj7pnVi1wGY | |
HCjzW/v/cIQUmbkvNfmNuJBO4vaEYR0OOgLPlvjqq9IjdFikis2eaFn2FVckVSug | |
e4xc3pRjsdUUuP/Y1I8N5rhLdw041DOLQjx7HouTH6KYsQudp5Zn9noR8fOwJ/+z | |
wZ7hJNqAuvVgmK77imeqUb+J/wABGU+3wSKCLST7A4iqfQWSpwXLcyteUOCs9LK8 | |
MA/g+0L6PwUisqTEfORfqAL4batZrhVdaamr8+RHRCECgYEA+qRC2eHgKnFewV/3 | |
IIVVeBKybp3t0wP7VhbG9LMo3qoMo9C9i1X1zQuf84rQ5pXg6Jo3Rqw8W01KBHPm | |
NML67I9nz3pCzyffE0lseIy7SKp3y8RFm4BINwUgVlnbDD+AFOIIxlRnqV2ldWBH | |
GEt+p3312WGhomOT7uhnh9WnkZECgYEA9+BAneYFipfGdfgLHdUTp9otE10GfpZ5 | |
HxQ7jaI0ytAcgMbaxct2FUOVTYWLHcE8u20alETdPk6XLorrHNSUbj9ItB5QyWOT | |
XVw7e71R1Z72xgCVx20R/jABEXAOliBw6zTtVNr/ZYwLgVMHHj+vK7aflfdNBmQn | |
UYVdfMDElRMCgYAWwV8IZQdzEwPlTo8jNrfBxQDKJjB3Xf8tm7fIc5OcU5f+L29l | |
/RHp4cpN1CaPKMBYndey5OQ97dBwgw09cQ5S99oW7iSuphIMsDfW4gAG4uMpbtJb | |
AdSMmjyLWnEWtZUtUDA3wWX/7G6fL3SE8iW3kyoE6GZCVgQSRqtPm8gw4QKBgGoq | |
zMJUkS8JTuGcOfavGtob4o6Wm3+Ap6QeIFvLi90KQgsOIQny2ULGTZ6Egk9eQsrs | |
MiQrUq+rLamrqoQQsPp/dH5hNazsT2P/ayLWtcRPb9bizUQ7fSdoHC0B192JS5QS | |
eUyM+DLgRtU/YJ8eG8MXV0b+QylnoEeUXbRfRFOtAoGBAKo2t8kVJK1n8pmvF8xR | |
o+7p4neCm9vVDcX3JSE2me0mlb4ZmN/lGpFcYB/cSqLHoHwhrG4Tu4IBULtdeLwB | |
36lvr7PMP8jpCHqND9Ilu/OqlmzKKEWMliTk0v68qF3abY63ORBXdhrV8RBWuCV5 | |
DhyGV1iLEJ6hLkK6dU1CLG/D | |
-----END PRIVATE KEY----- | |
""".trimIndent() | |
val rsaPublicKey = """ | |
-----BEGIN PUBLIC KEY----- | |
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8rALfmA9ZiZLIhlts/RA | |
tbuG2BrzDgiu5W5kDahBCJwMM8X9ZgRZSNxsc+7cF7046hexFGmYNlHvn1Wflm1/ | |
Yr7yaUKwBFMM24NR/N3bKPlWHkDQdODEFKUq30XtW3zcqOk8ykga9Znq3KSlWcWs | |
gjbq9VZhrC6c1Bmnp2x+RHMJUndfLDLIqANKKQR2YNlsCo30cC20wKHK+al0f/S4 | |
LZo28ncclV/CkjpdnAiyP7fv8RT/VhpfImXckOTowJmRCOi/4C1nvfUQNJyKz6k9 | |
vCOctmYcUy2M1VzgkU1oYm5eKOAatGI1JPCcTDxE/6Orjcc3C6WYCjsCIC8jli0y | |
wwIDAQAB | |
-----END PUBLIC KEY----- | |
""".trimIndent() | |
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(rsaPrivateKey.fromPKCS8toKeySpec()) | |
val publicKey = KeyFactory.getInstance("RSA").generatePublic(rsaPublicKey.fromX509toKeySpec()) | |
encrypt(plaintext, "RSA/ECB/PKCS1Padding", privateKey, publicKey) | |
sign(plaintext, "SHA256withRSA", privateKey, publicKey) | |
} | |
fun ecdsa(plaintext: String) { | |
/* | |
openssl ecparam -genkey -name secp256k1 -out key_ec.pem | |
openssl ec -in key_ec.pem -pubout -out key_ec.pub | |
openssl pkcs8 -in key_ec.pem -topk8 -nocrypt -out key_ec.key | |
*/ | |
val ecPrivateKey = """ | |
-----BEGIN PRIVATE KEY----- | |
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQg5jv2Fxm1CgQZv9cvRZd2 | |
hJ1a1hpD3h6lb9GZFwP92ImhRANCAATf48q1i04YGm9+cHj+oUwqYQslXzA7z7io | |
wlN1BoM+VRzBw2oK4azoM35vGt75C/MERC+hY9cMWjnLtpo2a6rO | |
-----END PRIVATE KEY----- | |
""".trimIndent() | |
val ecPublicKey = """ | |
-----BEGIN PUBLIC KEY----- | |
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE3+PKtYtOGBpvfnB4/qFMKmELJV8wO8+4 | |
qMJTdQaDPlUcwcNqCuGs6DN+bxre+QvzBEQvoWPXDFo5y7aaNmuqzg== | |
-----END PUBLIC KEY----- | |
""".trimIndent() | |
val privateKey = KeyFactory.getInstance("EC").generatePrivate(ecPrivateKey.fromPKCS8toKeySpec()) | |
val publicKey = KeyFactory.getInstance("EC").generatePublic(ecPublicKey.fromX509toKeySpec()) | |
sign(plaintext, "SHA256withECDSA", privateKey, publicKey) | |
} | |
private fun encrypt(plaintext: String, transformation: String, privateKey: PrivateKey, publicKey: PublicKey) { | |
val encrypt = Cipher.getInstance(transformation) | |
encrypt.init(Cipher.ENCRYPT_MODE, privateKey) | |
val ciphertext = encrypt.doFinal(plaintext.toByteArray()) | |
val decrypt = Cipher.getInstance(transformation) | |
decrypt.init(Cipher.DECRYPT_MODE, publicKey) | |
val decryptedPlaintext = String(decrypt.doFinal(ciphertext)) | |
println("[$transformation] matched: ${plaintext == decryptedPlaintext}, original: $plaintext, decrypted: $decryptedPlaintext") | |
} | |
private fun sign(plaintext: String, transformation: String, privateKey: PrivateKey, publicKey: PublicKey) { | |
val sign = Signature.getInstance(transformation) | |
sign.initSign(privateKey) | |
sign.update(plaintext.toByteArray()) | |
val signature = sign.sign() | |
val verify = Signature.getInstance(transformation) | |
verify.initVerify(publicKey) | |
verify.update(plaintext.toByteArray()) | |
val valid = verify.verify(signature) | |
println("[$transformation] valid: $valid, original: $plaintext") | |
} | |
private fun String.fromPKCS8toKeySpec(): PKCS8EncodedKeySpec { | |
return PKCS8EncodedKeySpec(PemReader.readFirstSectionAndClose(StringReader(this)).base64DecodedBytes) | |
} | |
private fun String.fromX509toKeySpec(): X509EncodedKeySpec { | |
return X509EncodedKeySpec(PemReader.readFirstSectionAndClose(StringReader(this)).base64DecodedBytes) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment