// SM4 CTR 计数器模式
// 依据 GB/T 32907-2016 分组密码 + NIST SP 800-38A 定义的 CTR 工作方式:
// 计数器为 16 字节大端整数,逐块加一(整块进位,全 1 回绕到 0),
// 密钥流 = ECB(counter),密文 = 明文 XOR 密钥流(无填充,长度与明文一致)。
///|
/// 把 16 字节计数器按 128 位大端整数加一(全 1 回绕到全 0)。
fn ctr_increment(cbe : FixedArray[Byte]) -> Unit {
let mut i = 15
while i >= 0 {
let v = cbe[i].to_int() + 1
if v <= 0xff {
cbe[i] = v.to_byte()
return
}
cbe[i] = 0
i = i - 1
}
}
///|
/// CTR 模式加密。`counter` 为 16 字节初始计数器,输出长度与明文一致。
/// CTR 加解密是同一变换(XOR 密钥流),`decrypt_ctr` 复用本函数。
pub fn encrypt_ctr(
key : Bytes,
counter : Bytes,
plaintext : Bytes,
) -> Result[Bytes, Sm4Error] {
if counter.length() != 16 {
return Err(InvalidIvLength(counter.length()))
}
let c = match sm4_of(key) {
Ok(c) => c
Err(e) => return Err(e)
}
let ctrbuf : FixedArray[Byte] = FixedArray::make(16, b'\x00')
for i in 0..<16 {
ctrbuf[i] = counter[i]
}
let out : FixedArray[Byte] = FixedArray::make(plaintext.length(), b'\x00')
let mut off = 0
while off < plaintext.length() {
let ks = c.encrypt_block(Bytes::from_array(ctrbuf))
let n = if plaintext.length() - off < 16 {
plaintext.length() - off
} else {
16
}
for i in 0.. Result[Bytes, Sm4Error] {
encrypt_ctr(key, counter, ciphertext)
}