// -*- go -*- // // Copyright (c) 2021-2024 Markku Rossi // // All rights reserved. // // Package cbc implements the cipher block chaining (CBC) mode of // operation for block ciphers. package cbc import ( "crypto/aes" ) // PadAES pads the data to AES cipher block boundary. The padding is // filled with byte value describing the padding length. Note that // data will be always padded. If the original data is already padded, // the padding will be one full AES block. func PadAES(data []byte) []byte { padLen := aes.BlockSize - len(data)%aes.BlockSize var padded [len(data) + padLen]byte for i := 0; i < padLen; i++ { padded[len(data)+i] = byte(padLen) } copy(padded, data) return padded } // EncryptAES128 encrypts the data in AES-CBC mode. The key specifies // the AES encryption key and iv is a random initialization // vector. The data must be padded to AES block size. // // // Case #1: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key // // Key : 0x06a9214036b8a15b512e03d534120006 // // IV : 0x3dafba429d9eb430b422da802c9fac41 // // Plaintext : "Single block msg" // // Ciphertext: 0xe353779c1079aeb82708942dbe77181a // // key := []byte{ // 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, // 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06, // } // iv := []byte{ // 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, // 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41, // } // plain := []byte("Single block msg") // // cipher := cbc.EncryptAES128(key, iv, plain) // => e353779c1079aeb82708942dbe77181a func EncryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte { var block [aes.BlockSize]byte copy(block, iv) var plain [aes.BlockSize]byte var cipher [len(data)]byte for i := 0; i < len(data)/aes.BlockSize; i++ { copy(plain, data[i*aes.BlockSize:]) for j := 0; j < aes.BlockSize; j++ { plain[j] ^= block[j] } //block = aes.Block128(key, plain) block = aes.EncryptBlock(key, plain) copy(cipher[i*aes.BlockSize:], block) } return cipher } func DecryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte { var block [aes.BlockSize]byte var cipher [aes.BlockSize]byte var plain [len(data)]byte for i := 0; i < len(data)/aes.BlockSize; i++ { copy(cipher, data[i*aes.BlockSize:]) block = aes.DecryptBlock(key, cipher) for j := 0; j < aes.BlockSize; j++ { block[j] ^= iv[j] } copy(plain[i*aes.BlockSize:], block) copy(iv, cipher) } return plain }