💨

About SSL/TLS Connection

2023/10/12に公開
  • 通信経路を暗号化するTLS(Transport Layer Security)が規格化されている
  • TLS は SSL(Secure Socket Layer)3.0 をbaseに TLS 標準化された

暗号化の仕組み

  • 以下の2つを組み合わせて暗号化通信を実現している
    • 共通鍵方式(AES)
    • 公開鍵方式(RSA) → 応用版: デジタル署名

共通鍵方式 (Advanced Encryption Standard)

暗号化/復号化 に用いられる鍵は同じものを利用する

AES暗号化方式

  • 暗号化アルゴリズムRijndael
    • 鍵長が長いほど多くのラウンドを繰り返して暗号化する
      • 128-AESは10ラウンド
      • 192-AESは12ラウンド
      • 256-AESは14ラウンド

公開鍵方式 (Rivest–Shamir–Adleman)

  • 暗号化/復号化 に用いられる鍵が異なる
    • 公開鍵で暗号化されたものは、秘密鍵のみで復号化可能
    • 秘密鍵で暗号化されたものは、公開鍵のみで復号化可能

RSA暗号化方式

  • 受信者が公開鍵と秘密鍵を生成する
  • 受信者は送信者に公開鍵を送る
  • 送信者がメッセージを公開鍵で暗号化する
  • 受信者がメッセージを秘密鍵で復号する

RSA暗号の応用事例

  • 秘密鍵を持つ側が、秘密鍵によって自身の署名を暗号化する
  • この署名を受け取った側が公開鍵によって署名を復号できれば、その署名が公開鍵と対になる秘密鍵で暗号化されたものだと判明する

→ デジタル署名

https://viewer.diagrams.net/?tags={}&highlight=0000ff&edit=_blank&layers=1&nav=1&title=TLS.drawio#Uhttps%3A%2F%2Fdrive.google.com%2Fuc%3Fid%3D1NYRoEjfhwxRqmrInqKYD0Np8f_YpAxI9%26export%3Ddownload

AES/RSAを使い分ける理由

  • RSAは安全性が高いがスループットが遅い
  • RSAに比べて、AESはハードウェア処理が行われ 3 ~ 10 倍程度の速度になる

そのため、最も重要な共通鍵の交換時のみRSAでの通信が行われ、その後は通信速度の速いAESによる暗号化が実施される

AES vs RSA Benchmark

というわけで、実際にbenchmarkを取ってみる

@Fork(1)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 5) //
@Measurement(iterations = 10) // CNT
open class EncryptionBenchmark {

    private lateinit var aesKey: SecretKey
    private lateinit var rsaKeyPair: KeyPair
    private lateinit var aesData: ByteArray
    private lateinit var rsaData: ByteArray
    private lateinit var encryptedAESData: ByteArray
    private lateinit var encryptedRSAData: ByteArray

    @Setup
    fun setup() {
        // AES key setup
        val keyGen = KeyGenerator.getInstance("AES")
        keyGen.init(256)
        aesKey = keyGen.generateKey()

        // RSA key setup
        val keyPairGen = KeyPairGenerator.getInstance("RSA")
        keyPairGen.initialize(2048)
        rsaKeyPair = keyPairGen.generateKeyPair()

        // Sample data for AES
        aesData = ByteArray(1024)
        SecureRandom().nextBytes(aesData)

        // Sample data for RSA (limited to 245 bytes)
        rsaData = ByteArray(245)
        SecureRandom().nextBytes(rsaData)

        // Encrypt data for decryption benchmark
        encryptedAESData = aesEncryption()
        encryptedRSAData = rsaEncryption()
    }

    @Benchmark
    fun aesEncryption(): ByteArray {
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        cipher.init(Cipher.ENCRYPT_MODE, aesKey)
        return cipher.doFinal(aesData)
    }

    @Benchmark
    fun aesDecrypt(): ByteArray {
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        cipher.init(Cipher.DECRYPT_MODE, aesKey, cipher.parameters)
        return cipher.doFinal(encryptedAESData)
    }

    @Benchmark
    fun rsaEncryption(): ByteArray {
        val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
        cipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.public)
        return cipher.doFinal(rsaData)
    }

    @Benchmark
    fun rsaDecrypt(): ByteArray {
        val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
        cipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.private)
        return cipher.doFinal(encryptedRSAData)
    }
}

Benchmark Summary

Benchmark                                 Mode  Cnt         Score         Error   Units
EncryptionBenchmark.aesEncryption        thrpt   10        69.760 ±       0.628  ops/ms
EncryptionBenchmark.rsaEncryption        thrpt   10        14.888 ±       0.553  ops/ms
EncryptionBenchmark.aesDecrypt           thrpt   10        67.767 ±       4.767  ops/ms
EncryptionBenchmark.rsaDecrypt           thrpt   10         0.650 ±       0.020  ops/ms
  • AES暗号化: 1ミリ秒あたり約69.760回の操作が可能
  • RSA暗号化: 1ミリ秒あたり約14.888回の操作が可能
  • AES復号化: 1ミリ秒あたり約67.767回の操作が可能
  • RSA復号化: 1ミリ秒あたり約0.650回の操作が可能

想定通りの結果

Discussion