Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
import crypto.aes
|
||||
import crypto.cipher
|
||||
|
||||
fn test_aes_cbc_double() {
|
||||
orig1 := []u8{len: 64, init: index}
|
||||
orig2 := []u8{len: 16, init: index}
|
||||
key := []u8{len: 16}
|
||||
iv := []u8{len: 16}
|
||||
|
||||
mut block := aes.new_cipher(key)
|
||||
mut en_cbc := cipher.new_cbc(block, iv)
|
||||
mut cip1 := []u8{len: orig1.len}
|
||||
mut cip2 := []u8{len: orig2.len}
|
||||
en_cbc.encrypt_blocks(mut cip1, orig1)
|
||||
en_cbc.encrypt_blocks(mut cip2, orig2)
|
||||
|
||||
mut block2 := aes.new_cipher(key)
|
||||
mut dec_cbc := cipher.new_cbc(block2, iv)
|
||||
mut plain1 := []u8{len: orig1.len}
|
||||
mut plain2 := []u8{len: orig2.len}
|
||||
dec_cbc.decrypt_blocks(mut plain1, cip1)
|
||||
dec_cbc.decrypt_blocks(mut plain2, cip2)
|
||||
|
||||
assert plain1 == orig1
|
||||
assert plain2 == orig2
|
||||
}
|
||||
|
||||
fn test_aes_cbc() {
|
||||
key := '6368616e676520746869732070617373'.bytes()
|
||||
iv := '1234567890123456'.bytes()
|
||||
str := '73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b'
|
||||
|
||||
mut src := str.bytes()
|
||||
|
||||
aes_cbc_en(mut src, key, iv)
|
||||
assert src.hex() == '20f36e39e6b73a040d3d39445d0282369033693076d1129a68a3364c00a81c508ec06ab94ff5104c321939fbfb9313c549fd68df100a8a23e8006a863733a8fd'
|
||||
|
||||
aes_cbc_de(mut src, key, iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_aes_cbc ok')
|
||||
}
|
||||
|
||||
fn aes_cbc_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := aes.new_cipher(key)
|
||||
mut mode := cipher.new_cbc(block, iv)
|
||||
mode.encrypt_blocks(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn aes_cbc_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := aes.new_cipher(key)
|
||||
mut mode := cipher.new_cbc(block, iv)
|
||||
mode.decrypt_blocks(mut src, src.clone())
|
||||
}
|
||||
@@ -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 []u8, key []u8, iv []u8) {
|
||||
block := aes.new_cipher(key)
|
||||
mut mode := cipher.new_cfb_encrypter(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn aes_cfb_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := aes.new_cipher(key)
|
||||
mut mode := cipher.new_cfb_decrypter(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import crypto.aes
|
||||
import crypto.cipher
|
||||
|
||||
fn test_aes_ctr() {
|
||||
key := '6368616e676520746869732070617373'.bytes()
|
||||
iv := '1234567890123456'.bytes()
|
||||
str := '73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b'
|
||||
|
||||
mut src := str.bytes()
|
||||
|
||||
aes_ctr_en(mut src, key, iv)
|
||||
assert src.hex() == '04380c1470ab2d8a0b3f9b4c1949b8ace811f22bc0a455a8946a3ea7a03e9f8440820f273ce749e955e4adb9e8f6ffde82bae507e0b6164b531d3eeb32f5beb5'
|
||||
|
||||
aes_ctr_de(mut src, key, iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_aes_ctr ok')
|
||||
}
|
||||
|
||||
fn aes_ctr_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := aes.new_cipher(key)
|
||||
mut mode := cipher.new_ctr(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn aes_ctr_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := aes.new_cipher(key)
|
||||
mut mode := cipher.new_ctr(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import crypto.aes
|
||||
import crypto.cipher
|
||||
|
||||
fn test_aes_ofb() {
|
||||
key := '6368616e676520746869732070617373'.bytes()
|
||||
iv := '1234567890123456'.bytes()
|
||||
str := '73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b'
|
||||
|
||||
mut src := str.bytes()
|
||||
|
||||
aes_ofb_en(mut src, key, iv)
|
||||
assert src.hex() == '04380c1470ab2d8a0b3f9b4c1949b8aca120db226fa0a848236f9904f786dfc39bc433b5d3870d1cfdef36debdee5e6f39b0e8e9462b0151d61e822944181b51'
|
||||
dump(src.hex())
|
||||
mut plaintext := src.clone()
|
||||
aes_ofb_de(mut plaintext, key, iv)
|
||||
assert plaintext.bytestr() == str
|
||||
dump(plaintext.bytestr())
|
||||
println('test_aes_ofb ok')
|
||||
}
|
||||
|
||||
fn aes_ofb_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := aes.new_cipher(key)
|
||||
mut mode := cipher.new_ofb(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn aes_ofb_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := aes.new_cipher(key)
|
||||
mut mode := cipher.new_ofb(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// 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 block chaining (CBC) mode.
|
||||
// CBC provides confidentiality by xoring (chaining) each plaintext block
|
||||
// with the previous ciphertext block before applying the block cipher.
|
||||
// See NIST SP 800-38A, pp 10-11
|
||||
// NOTE this will be moved to crypto.cipher interface (joe-c)
|
||||
module cipher
|
||||
|
||||
import crypto.internal.subtle
|
||||
|
||||
struct Cbc {
|
||||
mut:
|
||||
b Block
|
||||
block_size int
|
||||
iv []u8
|
||||
tmp []u8
|
||||
}
|
||||
|
||||
// free the resources taken by the Cbc `x`
|
||||
@[unsafe]
|
||||
pub fn (mut x Cbc) free() {
|
||||
$if prealloc {
|
||||
return
|
||||
}
|
||||
unsafe {
|
||||
// x.b.free() TODO add?
|
||||
x.iv.free()
|
||||
x.tmp.free()
|
||||
}
|
||||
}
|
||||
|
||||
// internal
|
||||
fn new_des_cbc(b Block, iv []u8) Cbc {
|
||||
return Cbc{
|
||||
b: b
|
||||
block_size: b.block_size
|
||||
iv: iv.clone()
|
||||
tmp: []u8{len: b.block_size}
|
||||
}
|
||||
}
|
||||
|
||||
// new_cbc returns a `DesCbc` which encrypts in cipher block chaining
|
||||
// mode, using the given Block. The length of iv must be the same as the
|
||||
// Block's block size.
|
||||
pub fn new_cbc(b Block, iv []u8) Cbc {
|
||||
if iv.len != b.block_size {
|
||||
panic('crypto.cipher.new_cbc_encrypter: IV length must equal block size')
|
||||
}
|
||||
return new_des_cbc(b, iv)
|
||||
}
|
||||
|
||||
// encrypt_blocks encrypts the blocks in `src_` to `dst_`.
|
||||
// Please note: `dst_` is mutable for performance reasons.
|
||||
pub fn (mut x Cbc) encrypt_blocks(mut dst_ []u8, src_ []u8) {
|
||||
unsafe {
|
||||
mut dst := *dst_
|
||||
mut src := src_
|
||||
if src.len % x.block_size != 0 {
|
||||
panic('crypto.cipher: input not full blocks')
|
||||
}
|
||||
if dst.len < src.len {
|
||||
panic('crypto.cipher: output smaller than input')
|
||||
}
|
||||
if subtle.inexact_overlap(dst[..src.len], src_) {
|
||||
panic('crypto.cipher: invalid buffer overlap')
|
||||
}
|
||||
mut iv := x.iv
|
||||
for src.len > 0 {
|
||||
// Write the xor to dst, then encrypt in place.
|
||||
xor_bytes(mut dst[..x.block_size], src[..x.block_size], iv)
|
||||
x.b.encrypt(mut dst[..x.block_size], dst[..x.block_size])
|
||||
// Move to the next block with this block as the next iv.
|
||||
iv = dst[..x.block_size]
|
||||
if x.block_size >= src.len {
|
||||
src = []
|
||||
} else {
|
||||
src = src[x.block_size..]
|
||||
}
|
||||
dst = dst[x.block_size..]
|
||||
}
|
||||
// Save the iv for the next crypt_blocks call.
|
||||
copy(mut x.iv, iv)
|
||||
}
|
||||
}
|
||||
|
||||
// decrypt_blocks decrypts the blocks in `src` to `dst`.
|
||||
// Please note: `dst` is mutable for performance reasons.
|
||||
pub fn (mut x Cbc) decrypt_blocks(mut dst []u8, src []u8) {
|
||||
if src.len % x.block_size != 0 {
|
||||
panic('crypto.cipher: input not full blocks')
|
||||
}
|
||||
if dst.len < src.len {
|
||||
panic('crypto.cipher: output smaller than input')
|
||||
}
|
||||
if subtle.inexact_overlap((*dst)[..src.len], src) {
|
||||
panic('crypto.cipher: invalid buffer overlap')
|
||||
}
|
||||
if src.len == 0 {
|
||||
return
|
||||
}
|
||||
// For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv).
|
||||
// To avoid making a copy each time, we loop over the blocks BACKWARDS.
|
||||
mut end := src.len
|
||||
mut start := end - x.block_size
|
||||
mut prev := start - x.block_size
|
||||
// Copy the last block of ciphertext in preparation as the new iv.
|
||||
copy(mut x.tmp, src[start..end])
|
||||
// Loop over all but the first block.
|
||||
for start > 0 {
|
||||
src_chunk := src[start..end]
|
||||
x.b.decrypt(mut (*dst)[start..end], src_chunk)
|
||||
xor_bytes(mut (*dst)[start..end], (*dst)[start..end], src[prev..start])
|
||||
end = start
|
||||
start = prev
|
||||
prev -= x.block_size
|
||||
}
|
||||
// The first block is special because it uses the saved iv.
|
||||
src_chunk := src[start..end]
|
||||
x.b.decrypt(mut (*dst)[start..end], src_chunk)
|
||||
xor_bytes(mut (*dst)[start..end], (*dst)[start..end], x.iv)
|
||||
// Set the new iv to the first block we copied earlier.
|
||||
x.iv, x.tmp = x.tmp, x.iv
|
||||
}
|
||||
|
||||
fn (mut x Cbc) set_iv(iv []u8) {
|
||||
if iv.len != x.iv.len {
|
||||
panic('cipher: incorrect length IV')
|
||||
}
|
||||
copy(mut x.iv, iv)
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// 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 []u8
|
||||
out []u8
|
||||
out_used int
|
||||
|
||||
decrypt bool
|
||||
}
|
||||
|
||||
// free the resources taken by the Cfb `x`
|
||||
@[unsafe]
|
||||
pub fn (mut x Cfb) free() {
|
||||
$if prealloc {
|
||||
return
|
||||
}
|
||||
unsafe {
|
||||
// x.b.free() TODO add?
|
||||
x.out.free()
|
||||
x.next.free()
|
||||
}
|
||||
}
|
||||
|
||||
// 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 []u8) 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 []u8) Cfb {
|
||||
return new_cfb(b, iv, true)
|
||||
}
|
||||
|
||||
fn new_cfb(b Block, iv []u8, decrypt bool) Cfb {
|
||||
block_size := b.block_size
|
||||
if iv.len != block_size {
|
||||
panic('cipher.new_cfb: IV length must be equal block size')
|
||||
}
|
||||
mut x := Cfb{
|
||||
b: b
|
||||
out: []u8{len: b.block_size}
|
||||
next: []u8{len: b.block_size}
|
||||
out_used: block_size
|
||||
decrypt: decrypt
|
||||
}
|
||||
copy(mut x.next, iv)
|
||||
return x
|
||||
}
|
||||
|
||||
// xor_key_stream xors each byte in the given slice with a byte from the key stream.
|
||||
pub fn (mut x Cfb) xor_key_stream(mut dst []u8, src []u8) {
|
||||
unsafe {
|
||||
mut local_dst := *dst
|
||||
mut local_src := src
|
||||
if local_dst.len < local_src.len {
|
||||
panic('crypto.cipher.xor_key_stream: output smaller than input')
|
||||
}
|
||||
|
||||
if subtle.inexact_overlap(local_dst[..src.len], local_src) {
|
||||
panic('crypto.cipher.xor_key_stream: invalid buffer overlap')
|
||||
}
|
||||
|
||||
for local_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(mut x.next[x.out_used..], local_src)
|
||||
}
|
||||
|
||||
n := xor_bytes(mut local_dst, local_src, x.out[x.out_used..])
|
||||
if !x.decrypt {
|
||||
copy(mut x.next[x.out_used..], local_dst)
|
||||
}
|
||||
local_dst = local_dst[n..]
|
||||
local_src = local_src[n..]
|
||||
x.out_used += n
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import crypto.cipher
|
||||
import crypto.des
|
||||
|
||||
struct StreamCipher {
|
||||
cipher cipher.Stream
|
||||
}
|
||||
|
||||
fn test_cfb_stream_cipher() ! {
|
||||
key := '123456789012345678901234'.bytes()
|
||||
iv := 'abcdegfh'.bytes()
|
||||
|
||||
block := des.new_cipher(key[..8])
|
||||
c := cipher.new_cfb_encrypter(block, iv)
|
||||
|
||||
s := StreamCipher{
|
||||
cipher: c
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// The source code refers to the go standard library, which will be combined with AES in the future.
|
||||
|
||||
module cipher
|
||||
|
||||
// A Block represents an implementation of block cipher
|
||||
// using a given key. It provides the capability to encrypt
|
||||
// or decrypt individual blocks. The mode implementations
|
||||
// extend that capability to streams of blocks.
|
||||
pub interface Block {
|
||||
block_size int // block_size returns the cipher's block size.
|
||||
encrypt(mut dst []u8, src []u8) // Encrypt encrypts the first block in src into dst.
|
||||
// Dst and src must overlap entirely or not at all.
|
||||
decrypt(mut dst []u8, src []u8) // Decrypt decrypts the first block in src into dst.
|
||||
// Dst and src must overlap entirely or not at all.
|
||||
}
|
||||
|
||||
// A Stream represents a stream cipher.
|
||||
pub interface Stream {
|
||||
mut:
|
||||
// xor_key_stream XORs each byte in the given slice with a byte from the
|
||||
// cipher's key stream. Dst and src must overlap entirely or not at all.
|
||||
//
|
||||
// If len(dst) < len(src), xor_key_stream should panic. It is acceptable
|
||||
// to pass a dst bigger than src, and in that case, xor_key_stream will
|
||||
// only update dst[:len(src)] and will not touch the rest of dst.
|
||||
//
|
||||
// Multiple calls to xor_key_stream behave as if the concatenation of
|
||||
// the src buffers was passed in a single run. That is, Stream
|
||||
// maintains state and does not reset at each xor_key_stream call.
|
||||
xor_key_stream(mut dst []u8, src []u8)
|
||||
}
|
||||
|
||||
// A BlockMode represents a block cipher running in a block-based mode (CBC,
|
||||
// ECB etc).
|
||||
pub interface BlockMode {
|
||||
block_size int // block_size returns the mode's block size.
|
||||
crypt_blocks(mut dst []u8, src []u8) // crypt_blocks encrypts or decrypts a number of blocks. The length of
|
||||
// src must be a multiple of the block size. Dst and src must overlap
|
||||
// entirely or not at all.
|
||||
//
|
||||
// If len(dst) < len(src), crypt_blocks should panic. It is acceptable
|
||||
// to pass a dst bigger than src, and in that case, crypt_blocks will
|
||||
// only update dst[:len(src)] and will not touch the rest of dst.
|
||||
//
|
||||
// Multiple calls to crypt_blocks behave as if the concatenation of
|
||||
// the src buffers was passed in a single run. That is, BlockMode
|
||||
// maintains state and does not reset at each crypt_blocks call.
|
||||
}
|
||||
|
||||
// AEAD provides an authenticated encryption with associated data for encryption (decryption).
|
||||
pub interface AEAD {
|
||||
// nonce_size returns the size of nonce (in bytes) used by this AEAD that must be
|
||||
// passed to `.encrypt` or `.decrypt`.
|
||||
nonce_size() int
|
||||
// overhead returns the maximum difference between the lengths of a plaintext and its ciphertext.
|
||||
overhead() int
|
||||
// encrypt encrypts and authenticates the provided plaintext along with the nonce and
|
||||
// additional data in `ad`. The nonce must be `nonce_size()` bytes long and unique
|
||||
// for all time, for a given key. It returns encrypted (and authenticated) ciphertext bytes
|
||||
// where its encoded form is up to implementation and not dictated by the interfaces.
|
||||
// Commonly, its contains encrypted text plus some authentication tag, and maybe some other bytes.
|
||||
encrypt(plaintext []u8, nonce []u8, ad []u8) ![]u8
|
||||
// decrypt decrypts and authenticates (verifies) the provided ciphertext along with a nonce, and
|
||||
// additional data. The nonce must be `nonce_size()` bytes long and both it and the additional data
|
||||
// must match the value passed to `encrypt`.
|
||||
// Its returns the verified plaintext on success, or errors on fails.
|
||||
decrypt(ciphertext []u8, nonce []u8, ad []u8) ![]u8
|
||||
}
|
||||
|
||||
// Utility routines
|
||||
|
||||
// fn dup(p []u8) []u8 {
|
||||
// q := make([]u8, p.len)
|
||||
// copy(mut q, p)
|
||||
// return q
|
||||
// }
|
||||
@@ -0,0 +1,85 @@
|
||||
// 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.
|
||||
//
|
||||
// Counter (CTR) mode.
|
||||
//
|
||||
// CTR converts a block cipher into a stream cipher by
|
||||
// repeatedly encrypting an incrementing counter and
|
||||
// xoring the resulting stream of data with the input.
|
||||
//
|
||||
// See NIST SP 800-38A, pp 13-15
|
||||
module cipher
|
||||
|
||||
import crypto.internal.subtle
|
||||
|
||||
struct Ctr {
|
||||
mut:
|
||||
b Block
|
||||
next []u8
|
||||
out []u8
|
||||
out_used int
|
||||
}
|
||||
|
||||
// free the resources taken by the Ctr `c`
|
||||
@[unsafe]
|
||||
pub fn (mut x Ctr) free() {
|
||||
$if prealloc {
|
||||
return
|
||||
}
|
||||
unsafe {
|
||||
// x.b.free() TODO add?
|
||||
x.out.free()
|
||||
x.next.free()
|
||||
}
|
||||
}
|
||||
|
||||
// new_ctr returns a Ctr which encrypts/decrypts using the given Block in
|
||||
// counter mode. The length of iv must be the same as the Block's block size.
|
||||
pub fn new_ctr(b Block, iv []u8) Ctr {
|
||||
block_size := b.block_size
|
||||
if iv.len != block_size {
|
||||
panic('cipher.new_cfb: IV length must be equal block size')
|
||||
}
|
||||
return Ctr{
|
||||
b: b
|
||||
out: []u8{len: b.block_size}
|
||||
next: iv.clone()
|
||||
out_used: block_size
|
||||
}
|
||||
}
|
||||
|
||||
// xor_key_stream xors each byte in the given slice with a byte from the key stream.
|
||||
pub fn (mut x Ctr) xor_key_stream(mut dst []u8, src []u8) {
|
||||
unsafe {
|
||||
mut local_dst := *dst
|
||||
mut local_src := src
|
||||
if local_dst.len < local_src.len {
|
||||
panic('crypto.cipher.xor_key_stream: output smaller than input')
|
||||
}
|
||||
|
||||
if subtle.inexact_overlap(local_dst[..local_src.len], local_src) {
|
||||
panic('crypto.cipher.xor_key_stream: invalid buffer overlap')
|
||||
}
|
||||
|
||||
for local_src.len > 0 {
|
||||
if x.out_used == x.out.len {
|
||||
x.b.encrypt(mut x.out, x.next)
|
||||
x.out_used = 0
|
||||
// increment counter
|
||||
for i := x.next.len - 1; i >= 0; i-- {
|
||||
x.next[i]++
|
||||
if x.next[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n := xor_bytes(mut local_dst, local_src, x.out[x.out_used..])
|
||||
|
||||
local_dst = local_dst[n..]
|
||||
local_src = local_src[n..]
|
||||
x.out_used += n
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import crypto.aes
|
||||
import crypto.cipher
|
||||
import crypto.des
|
||||
|
||||
struct StreamCipher {
|
||||
cipher cipher.Stream
|
||||
}
|
||||
|
||||
fn test_ctr_stream_cipher() ! {
|
||||
key := '123456789012345678901234'.bytes()
|
||||
iv := 'abcdegfh'.bytes()
|
||||
|
||||
block := des.new_cipher(key[..8])
|
||||
c := cipher.new_ctr(block, iv)
|
||||
|
||||
s := StreamCipher{
|
||||
cipher: c
|
||||
}
|
||||
}
|
||||
|
||||
fn test_ctr_byte_by_byte() {
|
||||
key := []u8{len: 16, init: index}
|
||||
iv := []u8{len: 16, init: index}
|
||||
txt := []u8{len: 32, init: index}
|
||||
mut out := []u8{len: 32}
|
||||
|
||||
mut ofb := cipher.new_ctr(aes.new_cipher(key), iv)
|
||||
for i in 0 .. 32 {
|
||||
ofb.xor_key_stream(mut out[i..i + 1], txt[i..i + 1])
|
||||
}
|
||||
assert out == [u8(10), 149, 9, 182, 69, 107, 246, 66, 249, 202, 158, 83, 202, 94, 228, 85,
|
||||
18, 114, 254, 135, 114, 13, 100, 129, 130, 195, 231, 20, 87, 185, 17, 195]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import crypto.des
|
||||
import crypto.cipher
|
||||
|
||||
const key = '123456789012345678901234'.bytes()
|
||||
const iv = 'abcdegfh'.bytes()
|
||||
const str = '73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b'
|
||||
|
||||
fn test_triple_des_cbc() {
|
||||
mut src := str.bytes()
|
||||
|
||||
triple_des_cbc_en(mut src, key, iv)
|
||||
assert src.hex() == '59d657007dc96062e8fffd574afda480ddba21fa06337ac5676eb4e40db256f2ab31ed442c0e4a82ef59b96292d24902c86b20c50bd8506e387775ca58f8c4fe'
|
||||
|
||||
triple_des_cbc_de(mut src, key, iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_triple_des_cbc ok')
|
||||
}
|
||||
|
||||
fn test_des_cbc() {
|
||||
mut src := str.bytes()
|
||||
|
||||
des_cbc_en(mut src, key[..8], iv)
|
||||
assert src.hex() == '198f94ca5989900ce73b26c3ce0005fa747b74d81e8cc5d529f96c1a2e7748d39f9900b9049cbfda35ef720d495b134f4f7dd2d7d3d910af488cdccd27d9f057'
|
||||
|
||||
des_cbc_de(mut src, key[..8], iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_des_cbc ok')
|
||||
}
|
||||
|
||||
fn des_cbc_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_cipher(key)
|
||||
mut mode := cipher.new_cbc(block, iv)
|
||||
mode.encrypt_blocks(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn des_cbc_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_cipher(key)
|
||||
mut mode := cipher.new_cbc(block, iv)
|
||||
mode.decrypt_blocks(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_cbc_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_cbc(block, iv)
|
||||
mode.encrypt_blocks(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_cbc_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_cbc(block, iv)
|
||||
mode.decrypt_blocks(mut src, src.clone())
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import crypto.des
|
||||
import crypto.cipher
|
||||
|
||||
const key = '123456789012345678901234'.bytes()
|
||||
const iv = 'abcdegfh'.bytes()
|
||||
const 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 []u8, key []u8, iv []u8) {
|
||||
block := des.new_cipher(key)
|
||||
mut mode := cipher.new_cfb_encrypter(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn des_cfb_de(mut src []u8, key []u8, iv []u8) {
|
||||
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 []u8, key []u8, iv []u8) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_cfb_encrypter(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_cfb_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_cfb_decrypter(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import crypto.des
|
||||
import crypto.cipher
|
||||
|
||||
const key = '123456789012345678901234'.bytes()
|
||||
const iv = 'abcdegfh'.bytes()
|
||||
const str = '73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b'
|
||||
|
||||
fn test_triple_des_ctr() {
|
||||
mut src := str.bytes()
|
||||
|
||||
triple_des_ctr_en(mut src, key, iv)
|
||||
assert src.hex() == '00d963619a67c84e5aa688174f259f4615768a516ec3fd10c98848f8626120db27fd2932130a4ba5e90acd5c347583bd4705770d41465b1ba11b4a523f449beb'
|
||||
|
||||
triple_des_ctr_de(mut src, key, iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_triple_des_ctr ok')
|
||||
}
|
||||
|
||||
fn test_des_ctr() {
|
||||
mut src := str.bytes()
|
||||
|
||||
des_ctr_en(mut src, key[..8], iv)
|
||||
assert src.hex() == '2743e2164b8604565f34bb120eb5dcd0f9db5f9a6498bdb678497c68c3cdda70500f4028159903d77d6b2a7ee4eb710c60e0f816deab4d919287c6a0cd9d2cd3'
|
||||
|
||||
des_ctr_de(mut src, key[..8], iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_des_ctr ok')
|
||||
}
|
||||
|
||||
fn des_ctr_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_cipher(key)
|
||||
mut mode := cipher.new_ctr(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn des_ctr_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_cipher(key)
|
||||
mut mode := cipher.new_ctr(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_ctr_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_ctr(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_ctr_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_ctr(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import crypto.des
|
||||
import crypto.cipher
|
||||
|
||||
const key = '123456789012345678901234'.bytes()
|
||||
const iv = 'abcdegfh'.bytes()
|
||||
const str = '73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b'
|
||||
|
||||
fn test_triple_des_ofb() {
|
||||
mut src := str.bytes()
|
||||
|
||||
triple_des_ofb_en(mut src, key, iv)
|
||||
assert src.hex() == '00d963619a67c84e46741a47e972e407121885af78b8ef64a9b835366e5314b8031940a9c33a4c0e1ce3b417c9fd04c3f99f31821ebfc9f8cb9e80cc50cfd91e'
|
||||
|
||||
triple_des_ofb_de(mut src, key, iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_triple_des_ofb ok')
|
||||
}
|
||||
|
||||
fn test_des_ofb() {
|
||||
mut src := str.bytes()
|
||||
|
||||
des_ofb_en(mut src, key[..8], iv)
|
||||
assert src.hex() == '2743e2164b860456c1313fb9b1196a70bb217dfad57be81cb10f368dd1ee13b06bb776eb52e0b4f6b1af32f44b8f094cfd3c0892021a2aa93f6a9e2139ba26f3'
|
||||
|
||||
des_ofb_de(mut src, key[..8], iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_des_ofb ok')
|
||||
}
|
||||
|
||||
fn des_ofb_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_cipher(key)
|
||||
mut mode := cipher.new_ofb(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn des_ofb_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_cipher(key)
|
||||
mut mode := cipher.new_ofb(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_ofb_en(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_ofb(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_ofb_de(mut src []u8, key []u8, iv []u8) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_ofb(block, iv)
|
||||
mode.xor_key_stream(mut src, src.clone())
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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.
|
||||
//
|
||||
// OFB (Output Feedback) Mode.
|
||||
// See NIST SP 800-38A, pp 13-15
|
||||
module cipher
|
||||
|
||||
import crypto.internal.subtle
|
||||
|
||||
struct Ofb {
|
||||
mut:
|
||||
b Block
|
||||
next []u8
|
||||
out []u8
|
||||
out_used int
|
||||
}
|
||||
|
||||
// new_ofb returns a Ofb that encrypts or decrypts using the block cipher b
|
||||
// in output feedback mode. The initialization vector iv's length must be equal
|
||||
// to b's block size.
|
||||
pub fn new_ofb(b Block, iv []u8) Ofb {
|
||||
block_size := b.block_size
|
||||
if iv.len != block_size {
|
||||
panic('cipher.new_ofb: IV length must be equal block size')
|
||||
}
|
||||
mut x := Ofb{
|
||||
b: b
|
||||
out: []u8{len: b.block_size}
|
||||
next: []u8{len: b.block_size}
|
||||
out_used: block_size
|
||||
}
|
||||
copy(mut x.next, iv)
|
||||
return x
|
||||
}
|
||||
|
||||
// xor_key_stream xors each byte in the given slice with a byte from the key stream.
|
||||
pub fn (mut x Ofb) xor_key_stream(mut dst []u8, src []u8) {
|
||||
unsafe {
|
||||
mut local_dst := *dst
|
||||
mut local_src := src
|
||||
if local_dst.len < local_src.len {
|
||||
panic('crypto.cipher.xor_key_stream: output smaller than input')
|
||||
}
|
||||
|
||||
if subtle.inexact_overlap(local_dst[..local_src.len], local_src) {
|
||||
panic('crypto.cipher.xor_key_stream: invalid buffer overlap')
|
||||
}
|
||||
|
||||
for local_src.len > 0 {
|
||||
if x.out_used == x.out.len {
|
||||
x.b.encrypt(mut x.out, x.next)
|
||||
x.out_used = 0
|
||||
copy(mut x.next, x.out)
|
||||
}
|
||||
n := xor_bytes(mut local_dst, local_src, x.out[x.out_used..])
|
||||
local_dst = local_dst[n..]
|
||||
local_src = local_src[n..]
|
||||
x.out_used += n
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import crypto.cipher
|
||||
import crypto.aes
|
||||
import crypto.des
|
||||
|
||||
struct StreamCipher {
|
||||
cipher cipher.Stream
|
||||
}
|
||||
|
||||
fn test_ofb_stream_cipher() ! {
|
||||
key := '123456789012345678901234'.bytes()
|
||||
iv := 'abcdegfh'.bytes()
|
||||
|
||||
block := des.new_cipher(key[..8])
|
||||
c := cipher.new_ofb(block, iv)
|
||||
|
||||
s := StreamCipher{
|
||||
cipher: c
|
||||
}
|
||||
}
|
||||
|
||||
fn test_ofb_byte_by_byte() {
|
||||
key := []u8{len: 16, init: index}
|
||||
iv := []u8{len: 16, init: index}
|
||||
txt := []u8{len: 32, init: index}
|
||||
mut out := []u8{len: 32}
|
||||
|
||||
mut ofb := cipher.new_ofb(aes.new_cipher(key), iv)
|
||||
for i in 0 .. 32 {
|
||||
ofb.xor_key_stream(mut out[i..i + 1], txt[i..i + 1])
|
||||
}
|
||||
assert out == [u8(10), 149, 9, 182, 69, 107, 246, 66, 249, 202, 158, 83, 202, 94, 228, 85,
|
||||
190, 246, 12, 182, 85, 194, 184, 92, 243, 121, 164, 215, 69, 34, 168, 124]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module cipher
|
||||
|
||||
// NOTE: Implement other versions (joe-c)
|
||||
// xor_bytes xors the bytes in a and b. The destination should have enough
|
||||
// space, otherwise xor_bytes will panic. Returns the number of bytes xor'd.
|
||||
pub fn xor_bytes(mut dst []u8, a []u8, b []u8) int {
|
||||
mut n := a.len
|
||||
if b.len < n {
|
||||
n = b.len
|
||||
}
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
safe_xor_bytes(mut dst, a, b, n)
|
||||
return n
|
||||
}
|
||||
|
||||
// safe_xor_bytes XORs the bytes in `a` and `b` into `dst` it does so `n` times.
|
||||
// Please note: `n` needs to be smaller or equal than the length of `a` and `b`.
|
||||
pub fn safe_xor_bytes(mut dst []u8, a []u8, b []u8, n int) {
|
||||
for i in 0 .. n {
|
||||
dst[i] = a[i] ^ b[i]
|
||||
}
|
||||
}
|
||||
|
||||
// xor_words XORs multiples of 4 or 8 bytes (depending on architecture.)
|
||||
// The slice arguments `a` and `b` are assumed to be of equal length.
|
||||
pub fn xor_words(mut dst []u8, a []u8, b []u8) {
|
||||
safe_xor_bytes(mut dst, a, b, b.len)
|
||||
}
|
||||
Reference in new issue
Block a user