Skip to content

Cryptographic Vulnerability: Insecure Algorithm

Cryptographic Vulnerability: Insecure Algorithm

Description

In cryptography, a cipher (or cypher) is an algorithm for performing encryption or decryption—a series of well-defined steps that can be followed as a procedure.

There are typically two families:

  • Blocker Cipher: A block cipher breaks down plaintext messages into fixed-size blocks before converting them into ciphertext using a key.
  • Stream Cipher: A stream cipher, on the other hand, breaks a plaintext message down into single bits, which then are converted individually into ciphertext using key bits.

Common cipher algorithms:

  • DES and Triple DES: Triple DES was designed to replace the original Data Encryption Standard (DES) algorithm, which hackers eventually learned to defeat with relative ease. At one time, Triple DES was the recommended standard and the most widely used symmetric algorithm in the industry. Triple DES uses three individual keys with 56 bits each. The total key length adds up to 168 bits, but experts would argue that 112-bits in key strength is more accurate. Despite slowly being phased out, Triple DES has, for the most part, been replaced by the Advanced Encryption Standard (AES).
  • AES: The Advanced Encryption Standard (AES) is the algorithm trusted as the standard by the U.S. Government and numerous organizations. Although it is highly efficient in 128-bit form, AES also uses keys of 192 and 256 bits for heavy-duty encryption purposes. AES is largely considered impervious to all attacks, except for brute force, which attempts to decipher messages using all possible combinations in the 128, 192, or 256-bit cipher.
  • RSA: RSA is a public-key encryption algorithm and the standard for encrypting data sent over the internet. It also happens to be one of the methods used in PGP and GPG programs. Unlike Triple DES, RSA is considered an asymmetric algorithm due to its use of a pair of keys. You've got your public key to encrypt the message and a private key to decrypt it. The result of RSA encryption is a huge batch of mumbo jumbo that takes attackers a lot of time and processing power to break.
  • ECC: Elliptic Curve Cryptography (ECC) is a key-based technique for encrypting data. ECC focuses on pairs of public and private keys for decryption and encryption of web traffic. ECC is frequently discussed in the context of the Rivest–Shamir–Adleman (RSA) cryptographic algorithm. RSA achieves one-way encryption of things like emails, data, and software using prime factorization.

DES, Triple DES are insecure and must not be used. Other algorithms suffer from some weaknesses caused by insecure cipher mode settings, key size or special key cases.

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)))
}

Recommendation

For secure and reliable encryption, it is crucial to use modern and robust cryptographic algorithms that have undergone extensive scrutiny and are widely adopted by the industry. Two recommended alternatives to the insecure DES and Triple DES are the Advanced Encryption Standard (AES) and Elliptic Curve Cryptography (ECC).

AES is widely recognized as a highly efficient and secure symmetric encryption algorithm. It offers key lengths of 128, 192, and 256 bits, making it suitable for various encryption purposes. AES has proven to be resilient against most known attacks, making it an excellent choice for data protection.

ECC, on the other hand, is an asymmetric encryption technique that uses pairs of public and private keys for encryption and decryption. ECC is known for providing strong security with shorter key lengths compared to other asymmetric algorithms like RSA. This results in faster encryption and decryption processes while maintaining a high level of security.

To ensure the utmost security when using any cryptographic algorithm, it is essential to follow best practices:

  • Key Length: Use key lengths that are considered secure. For AES, 128 bits are sufficient for most use cases, but you can opt for 192 or 256 bits for more sensitive data.

  • Cipher Mode: Always employ secure cipher mode settings, such as AES-GCM (Galois/Counter Mode) or AES-CBC (Cipher Block Chaining) with appropriate padding.

  • Key Management: Use secure storage mechanisms (Keystore for Android, Keychain for iOS) to safely store cryptographic keys.

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))
}

Standards

  • 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