From 5c0b7b0d05541c888d43609542aad78e72486797 Mon Sep 17 00:00:00 2001 From: Bastian Buck <59334447+bstnbuck@users.noreply.github.com> Date: Wed, 23 Feb 2022 09:55:16 +0100 Subject: [PATCH] crypto: implement Cipher Feedback (CFB) Mode for AES and DES (#13566) --- vlib/crypto/cipher/aes_cfb_test.v | 29 +++++++++++ vlib/crypto/cipher/cfb.v | 86 +++++++++++++++++++++++++++++++ vlib/crypto/cipher/des_cfb_test.v | 54 +++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 vlib/crypto/cipher/aes_cfb_test.v create mode 100644 vlib/crypto/cipher/cfb.v create mode 100644 vlib/crypto/cipher/des_cfb_test.v diff --git a/vlib/crypto/cipher/aes_cfb_test.v b/vlib/crypto/cipher/aes_cfb_test.v new file mode 100644 index 0000000000..db30e27b41 --- /dev/null +++ b/vlib/crypto/cipher/aes_cfb_test.v @@ -0,0 +1,29 @@ +import crypto.aes +import crypto.cipher + +fn test_aes_cfb() { + key := '6368616e676520746869732070617373'.bytes() + iv := '1234567890123456'.bytes() + str := '73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b' + + mut src := str.bytes() + + aes_cfb_en(mut src, key, iv) + assert src.hex() == '04380c1470ab2d8a0b3f9b4c1949b8ac57dfecca20ab539cd9862a262857ed3e4be1b1bb1d590f3c9eb760ef3d0c202b38e79ea53efbe4a3334f0a872e82f208' + + aes_cfb_de(mut src, key, iv) + assert src.bytestr() == str + println('test_aes_cfb ok') +} + +fn aes_cfb_en(mut src []byte, key []byte, iv []byte) { + block := aes.new_cipher(key) + mode := cipher.new_cfb_encrypter(block, iv) + mode.xor_key_stream(mut src, src.clone()) +} + +fn aes_cfb_de(mut src []byte, key []byte, iv []byte) { + block := aes.new_cipher(key) + mut mode := cipher.new_cfb_decrypter(block, iv) + mode.xor_key_stream(mut src, src.clone()) +} diff --git a/vlib/crypto/cipher/cfb.v b/vlib/crypto/cipher/cfb.v new file mode 100644 index 0000000000..6f041c6683 --- /dev/null +++ b/vlib/crypto/cipher/cfb.v @@ -0,0 +1,86 @@ +// The source code refers to the go standard library, which will be combined with AES in the future. + +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +// +// Cipher Feedback Mode (CFB). +// See NIST SP 800-38A, pp 11-13 + +module cipher + +import crypto.internal.subtle + +struct Cfb { +mut: + b Block + next []byte + out []byte + out_used int + + decrypt bool +} + +// new_cfb_encrypter returns a `Cfb` which encrypts with cipher feedback mode, +// using the given Block. The iv must be the same length as the Block's block +// size +pub fn new_cfb_encrypter(b Block, iv []byte) Cfb { + return new_cfb(b, iv, false) +} + +// new_cfb_decrypter returns a `Cfb` which decrypts with cipher feedback mode, +// using the given Block. The iv must be the same length as the Block's block +// size +pub fn new_cfb_decrypter(b Block, iv []byte) Cfb { + return new_cfb(b, iv, true) +} + +fn new_cfb(b Block, iv []byte, decrypt bool) Cfb { + block_size := b.block_size + if iv.len != block_size { + panic('cipher.new_cfb: IV length must be equal block size') + } + x := Cfb{ + b: b + out: []byte{len: b.block_size} + next: []byte{len: b.block_size} + out_used: block_size + decrypt: decrypt + } + + copy(x.next, iv) + + return x +} + +pub fn (x &Cfb) xor_key_stream(mut dst_ []byte, src_ []byte) { + unsafe { + mut dst := *dst_ + mut src := src_ + if dst.len < src.len { + panic('crypto.cipher.xor_key_stream: output smaller than input') + } + + if subtle.inexact_overlap(dst[..src.len], src) { + panic('crypto.cipher.xor_key_stream: invalid buffer overlap') + } + + for src.len > 0 { + if x.out_used == x.out.len { + x.b.encrypt(mut x.out, x.next) + x.out_used = 0 + } + + if x.decrypt { + copy(x.next[x.out_used..], src) + } + + n := xor_bytes(mut dst, src, x.out[x.out_used..]) + if !x.decrypt { + copy(x.next[x.out_used..], dst) + } + dst = dst[n..] + src = src[n..] + x.out_used += n + } + } +} diff --git a/vlib/crypto/cipher/des_cfb_test.v b/vlib/crypto/cipher/des_cfb_test.v new file mode 100644 index 0000000000..0aa172b360 --- /dev/null +++ b/vlib/crypto/cipher/des_cfb_test.v @@ -0,0 +1,54 @@ +import crypto.des +import crypto.cipher + +const ( + key = '123456789012345678901234'.bytes() + iv = 'abcdegfh'.bytes() + str = '73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b' +) + +fn test_triple_des_cfb() { + mut src := str.bytes() + + triple_des_cfb_en(mut src, key, iv) + assert src.hex() == '00d963619a67c84ef3e300e35c4d03fecbb3c4b1a2ee1abbff706dbe6da94ab5803359d1a6ac2b9cda703dbc32071abb2b1682fccdc92903b4e06187512e6d46' + + triple_des_cfb_de(mut src, key, iv) + assert src.bytestr() == str + println('test_triple_des_cfb ok') +} + +fn test_des_cfb() { + mut src := str.bytes() + + des_cfb_en(mut src, key[..8], iv) + assert src.hex() == '2743e2164b8604562f4ab73dd3d1bccb1fc08e77f34560b920ec8cce5c6a110ea1fcdc2a7ddd812e35387435de2985f6e636893db25a9d0683748edc145e1ef0' + + des_cfb_de(mut src, key[..8], iv) + assert src.bytestr() == str + println('test_des_cfb ok') +} + +fn des_cfb_en(mut src []byte, key []byte, iv []byte) { + block := des.new_cipher(key) + mode := cipher.new_cfb_encrypter(block, iv) + mode.xor_key_stream(mut src, src.clone()) +} + +fn des_cfb_de(mut src []byte, key []byte, iv []byte) { + block := des.new_cipher(key) + mut mode := cipher.new_cfb_decrypter(block, iv) + mode.xor_key_stream(mut src, src.clone()) +} + +fn triple_des_cfb_en(mut src []byte, key []byte, iv []byte) { + block := des.new_triple_des_cipher(key) + mode := cipher.new_cfb_encrypter(block, iv) + mode.xor_key_stream(mut src, src.clone()) +} + +fn triple_des_cfb_de(mut src []byte, key []byte, iv []byte) { + block := des.new_triple_des_cipher(key) + mode := cipher.new_cfb_decrypter(block, iv) + mode.xor_key_stream(mut src, src.clone()) +}