Symmetric Cryptography

Symmetric encryption is a method of encryption where the same key is used for both encryption and decryption of the data. In other words, the sender and the receiver must both have access to the same secret key. This key is used to transform plaintext into ciphertext (encryption) and back again (decryption). Symmetric encryption algorithms are generally faster and more efficient than asymmetric encryption algorithms, making them suitable for encrypting large amounts of data.

  • Examples of Symmetric Encryption Algorithms
    • AES (Advanced Encryption Standard): AES is one of the most widely used symmetric encryption algorithms. It uses keys of 128, 192, or 256 bits and operates on blocks of data.
    • DES (Data Encryption Standard): DES was one of the earliest symmetric encryption algorithms but is now considered obsolete due to its small key size (56 bits) and vulnerability to brute force attacks. It's been superseded by Triple DES (3DES), which applies the DES encryption algorithm three times to each data block.
  • Use Cases:
    • Data Encryption: It's used to encrypt sensitive data stored on computers, servers, or transmitted over networks, ensuring confidentiality.
    • Secure Communication: Symmetric encryption is employed in secure communication protocols like SSL/TLS to establish secure connections between clients and servers.
    • File Encryption: It's used to encrypt files and folders to prevent unauthorized access.
    • Disk Encryption: Symmetric encryption is used to encrypt entire disks or partitions, protecting the data stored on them from unauthorized access if the device is lost or stolen.
  • Limitations:
    • Key Distribution: One of the main challenges with symmetric encryption is securely distributing the secret key to all parties involved. If an attacker intercepts the key during transmission, they can decrypt the data.
    • Key Management: As the number of users and devices increases, managing and securely storing keys becomes more complex.
    • Lack of Authentication: Symmetric encryption alone does not provide authentication, meaning there's no assurance that the sender or receiver of the data is who they claim to be. Additional mechanisms like digital signatures are needed for authentication.
    • Key Exchange Overhead: In scenarios where secure key exchange is necessary, the overhead of securely exchanging symmetric keys can be significant, especially in large-scale systems.

Go Example

package main

import (
  "bytes"
  "crypto/aes"
  "crypto/cipher"
  "crypto/des"
  "crypto/rand"
  "errors"
  "fmt"
  "io"
)

func main() {
  // AES Encryption and Decryption Example
  aesKey := []byte("AES256Key-32Characters1234567890")
  plaintext := []byte("Hello, AES!")

  // Encrypt using AES
  aesCipherText, err := encryptAES(plaintext, aesKey)
  if err != nil {
    fmt.Println("Error encrypting with AES:", err)
    return
  }

  // Decrypt using AES
  aesDecryptedText, err := decryptAES(aesCipherText, aesKey)
  if err != nil {
    fmt.Println("Error decrypting with AES:", err)
    return
  }
  fmt.Println("AES Decrypted text:", string(aesDecryptedText))

  // DES Encryption and Decryption Example
  desKey := []byte("DESCrypt")
  plaintext = []byte("Hello, DES!")

  // Encrypt using DES
  desCipherText, err := encryptDES(plaintext, desKey)
  if err != nil {
    fmt.Println("Error encrypting with DES:", err)
    return
  }

  // Decrypt using DES
  desDecryptedText, err := decryptDES(desCipherText, desKey)
  if err != nil {
    fmt.Println("Error decrypting with DES:", err)
    return
  }
  fmt.Println("DES Decrypted text:", string(desDecryptedText))
}

func padPKCS7(src []byte, blockSize int) []byte {
  padLen := blockSize - len(src)%blockSize
  padding := bytes.Repeat([]byte{byte(padLen)}, padLen)
  return append(src, padding...)
}

func unpadPKCS7(src []byte) ([]byte, error) {
  length := len(src)
  unpadding := int(src[length-1])
  if unpadding > length {
    return nil, errors.New("invalid padding")
  }
  return src[:length-unpadding], nil
}

func encryptAES(plaintext, key []byte) ([]byte, error) {
  block, err := aes.NewCipher(key)
  if err != nil {
    return nil, err
  }
  plaintext = padPKCS7(plaintext, aes.BlockSize)
  ciphertext := make([]byte, aes.BlockSize+len(plaintext))
  iv := ciphertext[:aes.BlockSize]
  if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    return nil, err
  }
  mode := cipher.NewCBCEncrypter(block, iv)
  mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
  return ciphertext, nil
}

func decryptAES(ciphertext, key []byte) ([]byte, error) {
  block, err := aes.NewCipher(key)
  if err != nil {
    return nil, err
  }
  if len(ciphertext) < aes.BlockSize {
    return nil, fmt.Errorf("ciphertext too short")
  }
  iv := ciphertext[:aes.BlockSize]
  ciphertext = ciphertext[aes.BlockSize:]
  mode := cipher.NewCBCDecrypter(block, iv)
  mode.CryptBlocks(ciphertext, ciphertext)
  return unpadPKCS7(ciphertext)
}

func padPKCS5(src []byte, blockSize int) []byte {
  padLen := blockSize - len(src)%blockSize
  padding := bytes.Repeat([]byte{byte(padLen)}, padLen)
  return append(src, padding...)
}

func unpadPKCS5(src []byte) ([]byte, error) {
  length := len(src)
  unpadding := int(src[length-1])
  if unpadding > length {
    return nil, errors.New("invalid padding")
  }
  return src[:length-unpadding], nil
}

func encryptDES(plaintext, key []byte) ([]byte, error) {
  block, err := des.NewCipher(key)
  if err != nil {
    return nil, err
  }
  plaintext = padPKCS5(plaintext, des.BlockSize)
  ciphertext := make([]byte, des.BlockSize+len(plaintext))
  iv := ciphertext[:des.BlockSize]
  if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    return nil, err
  }
  mode := cipher.NewCBCEncrypter(block, iv)
  mode.CryptBlocks(ciphertext[des.BlockSize:], plaintext)
  return ciphertext, nil
}

func decryptDES(ciphertext, key []byte) ([]byte, error) {
  block, err := des.NewCipher(key)
  if err != nil {
    return nil, err
  }
  if len(ciphertext) < des.BlockSize {
    return nil, fmt.Errorf("ciphertext too short")
  }
  iv := ciphertext[:des.BlockSize]
  ciphertext = ciphertext[des.BlockSize:]
  mode := cipher.NewCBCDecrypter(block, iv)
  mode.CryptBlocks(ciphertext, ciphertext)
  return unpadPKCS5(ciphertext)
}

The result you obtain should be:

AES Decrypted text: Hello, AES!
DES Decrypted text: Hello, DES!