mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 18:37:26 +08:00
* v2.1.0 [omit consensus and adjacent] - this commit will be amended with the full release after the file copy is complete * 2.1.0 main node rollup
136 lines
3.4 KiB
Go
136 lines
3.4 KiB
Go
// -*- go -*-
|
|
//
|
|
// Copyright (c) 2024 Markku Rossi
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
|
|
// Package cts implements the ciphertext stealing (CTS) mode of
|
|
// operation for block ciphers. The implementation uses the CTS-3
|
|
// (Kerberos) variant for formatting the cipher text.
|
|
package cts
|
|
|
|
import (
|
|
"crypto/aes"
|
|
)
|
|
|
|
// EncryptAES128 encrypts the data in AES-CTS mode. The key specifies
|
|
// the AES encryption key and iv is a random initialization vector.
|
|
//
|
|
// key := []byte{
|
|
// 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
|
|
// 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
|
|
// }
|
|
// var iv [16]byte
|
|
// data := []byte{
|
|
// 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
|
|
// 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
|
|
// 0x20,
|
|
// }
|
|
// cipher := cts.EncryptAES128(key, iv, data)
|
|
// => c6353568f2bf8cb4d8a580362da7ff7f97
|
|
func EncryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte {
|
|
numBlocks := len(data) / aes.BlockSize
|
|
tail := len(data) % aes.BlockSize
|
|
|
|
if tail != 0 {
|
|
numBlocks++
|
|
} else {
|
|
tail = aes.BlockSize
|
|
}
|
|
if numBlocks < 2 {
|
|
panic("cts.EncryptAES128: input must be at least 2 block")
|
|
}
|
|
var block [aes.BlockSize]byte
|
|
copy(block, iv)
|
|
|
|
var plain [aes.BlockSize]byte
|
|
var cipher [len(data)]byte
|
|
|
|
// Standard CBC for the first numBlocks-1 blocks.
|
|
for i := 0; i < numBlocks-1; i++ {
|
|
copy(plain, data[i*aes.BlockSize:])
|
|
for j := 0; j < aes.BlockSize; j++ {
|
|
plain[j] ^= block[j]
|
|
}
|
|
block = aes.EncryptBlock(key, plain)
|
|
if i < numBlocks-2 {
|
|
// Store standard CBC output block.
|
|
copy(cipher[i*aes.BlockSize:], block)
|
|
} else {
|
|
// Store last ciphertext block.
|
|
copy(cipher[(numBlocks-1)*aes.BlockSize:], block)
|
|
}
|
|
}
|
|
|
|
// Create last input block.
|
|
copy(plain, data[(numBlocks-1)*aes.BlockSize:])
|
|
for i := tail; i < aes.BlockSize; i++ {
|
|
plain[i] = 0
|
|
}
|
|
for j := 0; j < aes.BlockSize; j++ {
|
|
plain[j] ^= block[j]
|
|
}
|
|
block = aes.EncryptBlock(key, plain)
|
|
copy(cipher[(numBlocks-2)*aes.BlockSize:], block)
|
|
|
|
return cipher
|
|
}
|
|
|
|
// DecryptAES128 decrypts the data that is encrypted in AES-CTS
|
|
// mode. The key specifies the AES encryption key and iv is the random
|
|
// initialization vector used in encryption.
|
|
func DecryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte {
|
|
numBlocks := len(data) / aes.BlockSize
|
|
tail := len(data) % aes.BlockSize
|
|
|
|
if tail != 0 {
|
|
numBlocks++
|
|
} else {
|
|
tail = aes.BlockSize
|
|
}
|
|
|
|
if numBlocks < 2 {
|
|
panic("cts.DecryptAES128: input must be at least 2 blocks")
|
|
}
|
|
var block [aes.BlockSize]byte
|
|
var cipher [aes.BlockSize]byte
|
|
var tmp2 [aes.BlockSize]byte
|
|
var plain [len(data)]byte
|
|
|
|
// Standard CBC for the first numBlocks-2 blocks.
|
|
for i := 0; i < numBlocks-2; i++ {
|
|
copy(cipher, data[i*aes.Blocks:])
|
|
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)
|
|
}
|
|
|
|
// Decrypt second-to-last cipher block.
|
|
copy(cipher, data[(numBlocks-2)*aes.BlockSize:])
|
|
tmp := aes.DecryptBlock(key, cipher)
|
|
|
|
// Create padded last cipher block.
|
|
copy(tmp2, data[(numBlocks-1)*aes.BlockSize:])
|
|
copy(tmp2[tail:], tmp[tail:])
|
|
|
|
// Decrypt second-to-last block.
|
|
block = aes.DecryptBlock(key, tmp2)
|
|
for j := 0; j < aes.BlockSize; j++ {
|
|
block[j] ^= iv[j]
|
|
}
|
|
copy(plain[(numBlocks-2)*aes.BlockSize:], block)
|
|
copy(iv, tmp2)
|
|
|
|
// Finalize last block.
|
|
for j := 0; j < aes.BlockSize; j++ {
|
|
tmp[j] ^= iv[j]
|
|
}
|
|
copy(plain[(numBlocks-1)*aes.BlockSize:], tmp)
|
|
|
|
return plain
|
|
}
|