コンテンツにスキップ

Cryptographic Vulnerability: Insecure Algorithm

暗号化の脆弱性: 安全でないアルゴリズム

説明

暗号化において、暗号(cipher または cypher)は暗号化または復号化を実行するためのアルゴリズムであり、 手順として従うことができる一連の明確に定義されたステップです。

通常、2つのファミリーがあります:

  • ブロック暗号 (Block Cipher): ブロック暗号は、平文メッセージを固定サイズのブロックに分割してから、キーを使用して 暗号文に変換します。
  • ストリーム暗号 (Stream Cipher): 一方、ストリーム暗号は、平文メッセージを単一のビットに分割し、その後キービットを使用して 個別に暗号文に変換します。

一般的な暗号アルゴリズム:

  • DES および Triple DES: Triple DESは、元のData Encryption Standard (DES) アルゴリズムを置き換えるように設計されました。 これは後に攻撃者によって比較的簡単に解読されるようになりました。かつては、Triple DESが推奨される標準であり、 業界で最も広く使用されている対称アルゴリズムでした。Triple DESは、それぞれ56ビットの3つの個別の鍵を使用します。 合計の鍵長は168ビットになりますが、専門家は112ビットの鍵強度がより正確であると主張するでしょう。 ゆっくりと段階的に廃止されているものの、Triple DESはほとんどの場合、Advanced Encryption Standard(AES)に置き換えられています。
  • AES: Advanced Encryption Standard (AES) は、米国政府や多数の組織から標準として信頼されているアルゴリズムです。そして 多くの組織によって標準として信頼されているアルゴリズムです。128ビット形式でも非常に効率的ですが、AESは192ビットおよび256ビットの鍵も 高負荷の暗号化目的に使用されます。AESは、総当たり攻撃(ブルートフォース攻撃)を除き、すべての攻撃に対して影響を受けないと広く考えられています。総当たり攻撃は、 128、192、または256ビットの暗号内のすべての可能な組み合わせを使用してメッセージの解読を試みます。
  • RSA: RSAは公開鍵暗号アルゴリズムであり、インターネット上で送信されるデータを暗号化するための標準です。また、 PGPおよびGPGプログラムで使用される方法の1つでもあります。Triple DESとは異なり、RSAは その一対の鍵を使用するため、非対称アルゴリズムと見なされます。メッセージを暗号化するための 公開鍵があり、メッセージを復号化するための秘密鍵があります。RSA暗号化の結果は、 攻撃者が解読するのに多大な時間と処理能力を要する膨大な暗号文のバッチとなります。
  • ECC: Elliptic Curve Cryptography(ECC)は、データを暗号化するための鍵ベースの技術です。ECCは、公開鍵のペアに焦点を当てています。 および秘密鍵ペアを使用して、Webトラフィックの暗号化と復号化を行います。ECCは、 Rivest–Shamir–Adleman(RSA)暗号アルゴリズムのコンテキストで頻繁に議論されます。RSAは、 素因数分解を使用して、電子メール、データ、ソフトウェアなどの一方向暗号化を実現します。

DESTriple DESは安全ではないため、使用してはなりません。他のアルゴリズムは、安全でない暗号モード設定や 鍵のサイズ、または特別な鍵のケースに起因するいくつかの弱点があります。

import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:crypto/crypto.dart';
import 'package:pointycastle/export.dart' as pc;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Insecure Encryption Demo'),
        ),
        body: EncryptionWidget(),
      ),
    );
  }
}

class EncryptionWidget extends StatefulWidget {
  @override
  _EncryptionWidgetState createState() => _EncryptionWidgetState();
}

class _EncryptionWidgetState extends State<EncryptionWidget> {
  final _controller = TextEditingController();
  String _encryptedText = '';

  void _encryptText() {
    final key = utf8.encode('insecurekey');
    final iv = Uint8List(8);
    final s = pc.SICStreamCipher(pc.DESEngine())
      ..init(true, pc.ParametersWithIV(pc.KeyParameter(key), iv));
    final input = utf8.encode(_controller.text);
    final output = s.process(input);
    setState(() {
      _encryptedText = base64.encode(output);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        TextField(
          controller: _controller,
          decoration: InputDecoration(
            labelText: 'Enter text to encrypt',
          ),
        ),
        RaisedButton(
          onPressed: _encryptText,
          child: Text('Encrypt'),
        ),
        Text('Encrypted text: $_encryptedText'),
      ],
    );
  }
}
import Foundation
import CommonCrypto

func DES_Encrypt(input: String, key: String) -> String {
    let data = input.data(using: String.Encoding.utf8)!
    let keyData = key.data(using: String.Encoding.utf8)!
    let keyBytes = keyData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
        return bytes
    }
    let dataLength = Int(data.count)
    let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: dataLength + kCCBlockSizeDES)
    let bufferPtr = UnsafeMutableRawPointer(buffer)
    let bufferPtrBytes = bufferPtr.bindMemory(to: Void.self, capacity: dataLength)
    let iv = [UInt8](repeating: 0, count: kCCBlockSizeDES)
    var numBytesEncrypted :size_t = 0
    let cryptStatus = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmDES), CCOptions(kCCOptionPKCS7Padding), keyBytes, kCCKeySizeDES, iv, data.bytes, dataLength, bufferPtrBytes, dataLength + kCCBlockSizeDES, &numBytesEncrypted)
    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        let encryptedData = Data(bytes: UnsafePointer<UInt8>(buffer), count: numBytesEncrypted)
        buffer.deallocate()
        return encryptedData.base64EncodedString()
    } else {
        buffer.deallocate()
        return ""
    }
}

func main() {
    print("Enter text to encrypt:")
    let input = readLine() ?? ""
    print("Enter encryption key:")
    let key = readLine() ?? ""
    let encrypted = DES_Encrypt(input: input, key: key)
    print("Encrypted text: \(encrypted)")
}

main()
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.DESKeySpec
import java.util.*

fun main(args: Array<String>) {
    val scanner = Scanner(System.`in`)
    println("Enter text to encrypt:")
    val text = scanner.nextLine()
    println("Enter DES key:")
    val key = scanner.nextLine()

    val encryptedText = encrypt(text, key)
    println("Encrypted text: $encryptedText")

    val decryptedText = decrypt(encryptedText, key)
    println("Decrypted text: $decryptedText")
}

fun encrypt(text: String, key: String): String {
    val desKey = SecretKeyFactory.getInstance("DES").generateSecret(DESKeySpec(key.toByteArray()))
    val cipher = Cipher.getInstance("DES")
    cipher.init(Cipher.ENCRYPT_MODE, desKey)
    return Base64.getEncoder().encodeToString(cipher.doFinal(text.toByteArray()))
}

fun decrypt(text: String, key: String): String {
    val desKey = SecretKeyFactory.getInstance("DES").generateSecret(DESKeySpec(key.toByteArray()))
    val cipher = Cipher.getInstance("DES")
    cipher.init(Cipher.DECRYPT_MODE, desKey)
    return String(cipher.doFinal(Base64.getDecoder().decode(text)))
}

推奨事項

安全で信頼性の高い暗号化のためには、徹底的な検証を受け、業界で広く採用されている最新で堅牢な暗号アルゴリズムを使用することが不可欠です。安全でないDESおよびTriple DESに代わる2つの推奨される選択肢は、Advanced Encryption Standard (AES) およびElliptic Curve Cryptography (ECC) です。

AESは、非常に効率的で安全な対称暗号アルゴリズムとして広く認識されています。128ビット、192ビット、256ビットの鍵長を提供し、さまざまな暗号化の目的に適しています。AESは既知の攻撃の大部分に対して耐性があることが証明されており、データ保護のための優れた選択肢となっています。

一方、ECCは公開鍵と秘密鍵のペアを使用して暗号化と復号化を行う非対称暗号化技術です。ECCは、RSAのような他の非対称アルゴリズムと比較して、短い鍵長で強力なセキュリティを提供することで知られています。これにより、高いセキュリティレベルを維持しながら、暗号化と復号化のプロセスがより高速になります。

暗号アルゴリズムを使用する際に最大限のセキュリティを確保するためには、以下のベストプラクティスに従うことが不可欠です:

  • 鍵長: 安全と見なされる鍵長を使用してください。AESの場合、ほとんどのユースケースで128ビットで十分ですが、より機密性の高いデータには192ビットまたは256ビットを選択できます。

  • 暗号モード: AES-GCM(Galois/Counter Mode)またはAES-CBC(Cipher Block Chaining)と適切なパディングなど、常に安全な暗号モード設定を採用してください。

  • 鍵管理: 安全な保存メカニズム(Androidの場合はKeystore、iOSの場合はKeychain)を使用して、暗号鍵を安全に保存してください。

import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pointycastle/export.dart' as pc;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Secure Encryption Demo'),
        ),
        body: EncryptionWidget(),
      ),
    );
  }
}

class EncryptionWidget extends StatefulWidget {
  @override
  _EncryptionWidgetState createState() => _EncryptionWidgetState();
}

class _EncryptionWidgetState extends State<EncryptionWidget> {
  final _controller = TextEditingController();
  String _encryptedText = '';

  void _encryptText() {
    final key = pc.KeyParameter(Uint8List.fromList(utf8.encode('securekey123456789012345678901234'))); // 32 bytes for AES-256
    final iv = Uint8List(12); // 12 bytes for GCM IV
    final cipher = pc.GCMBlockCipher(pc.AESFastEngine())
      ..init(true, pc.AEADParameters(key, 128, iv));
    final input = utf8.encode(_controller.text);
    final output = cipher.process(Uint8List.fromList(input));
    setState(() {
      _encryptedText = base64.encode(output);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        TextField(
          controller: _controller,
          decoration: InputDecoration(
            labelText: 'Enter text to encrypt',
          ),
        ),
        RaisedButton(
          onPressed: _encryptText,
          child: Text('Encrypt'),
        ),
        Text('Encrypted text: $_encryptedText'),
      ],
    );
  }
}
import Foundation
import CryptoKit

func AES_GCM_Encrypt(input: String, key: String) -> String {
    guard let data = input.data(using: .utf8),
          let keyData = key.data(using: .utf8) else {
        return ""
    }

    let iv = Data(count: AES.GCM.nonceSize)

    do {
        let sealedData = try! AES.GCM.seal(plainData!, using: key, nonce: AES.GCM.Nonce(data:nonce!))
        let encryptedContent = try! sealedData.combined!
        return sealedData.ciphertext.base64EncodedString()
    } catch {
        return ""
    }
}

print("Enter text to encrypt:")
if let input = readLine() {
    print("Enter encryption key:")
    if let key = readLine() {
        let encrypted = AES_GCM_Encrypt(input: input, key: key)
        print("Encrypted text: \(encrypted)")
    }
}
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
import java.security.spec.KeySpec
import java.util.*

fun main(args: Array<String>) {
    val scanner = Scanner(System.`in`)
    println("Enter text to encrypt:")
    val text = scanner.nextLine()
    println("Enter AES key:")
    val key = scanner.nextLine()

    val salt = ByteArray(16)
    SecureRandom().nextBytes(salt)
    val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
    val spec: KeySpec = PBEKeySpec(key.toCharArray(), salt, 65536, 256)
    val secretKey = factory.generateSecret(spec)
    val secretKeySpec = SecretKeySpec(secretKey.encoded, "AES")

    val encryptedText = encrypt(text, secretKeySpec)
    println("Encrypted text: $encryptedText")

    val decryptedText = decrypt(encryptedText, secretKeySpec)
    println("Decrypted text: $decryptedText")
}

fun encrypt(text: String, key: SecretKey): String {
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    val iv = ByteArray(12)
    SecureRandom().nextBytes(iv)
    val gcmSpec = GCMParameterSpec(128, iv)
    cipher.init(Cipher.ENCRYPT_MODE, key, gcmSpec)
    val encryptedBytes = cipher.doFinal(text.toByteArray())
    val encryptedTextAndIV = ByteArray(iv.size + encryptedBytes.size)
    System.arraycopy(iv, 0, encryptedTextAndIV, 0, iv.size)
    System.arraycopy(encryptedBytes, 0, encryptedTextAndIV, iv.size, encryptedBytes.size)
    return Base64.getEncoder().encodeToString(encryptedTextAndIV)
}

fun decrypt(text: String, key: SecretKey): String {
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    val decodedText = Base64.getDecoder().decode(text)
    val iv = decodedText.copyOfRange(0, 12)
    val encryptedBytes = decodedText.copyOfRange(12, decodedText.size)
    val gcmSpec = GCMParameterSpec(128, iv)
    cipher.init(Cipher.DECRYPT_MODE, key, gcmSpec)
    return String(cipher.doFinal(encryptedBytes))
}

リンク

標準

  • OWASP_MASVS_L1:
    • MSTG_CRYPTO_2
    • MSTG_CRYPTO_3
    • MSTG_CRYPTO_4
  • OWASP_MASVS_L2:
    • MSTG_CRYPTO_2
    • MSTG_CRYPTO_3
    • MSTG_CRYPTO_4
  • PCI_STANDARDS:
    • REQ_3_6
    • REQ_3_7
    • REQ_4_2
    • REQ_6_2
  • OWASP_MASVS_v2_1:
    • MASVS_CRYPTO_1
    • MASVS_CRYPTO_2
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_4_1
    • CC_6_7
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5
  • CNIL_FOR_DEVELOPERS:
    • DEVELOPERS_4_1_4
  • HIPAA_CONTROLS:
    • SECURITY252
    • SECURITY212
    • SECURITY213