Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+56
View File
@@ -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())
}
+29
View File
@@ -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())
}
+29
View File
@@ -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())
}
+31
View File
@@ -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())
}
+133
View File
@@ -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)
}
+98
View File
@@ -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
}
}
}
+18
View File
@@ -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
}
}
+76
View File
@@ -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
// }
+85
View File
@@ -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
}
}
}
+33
View File
@@ -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]
}
+52
View File
@@ -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())
}
+52
View File
@@ -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())
}
+52
View File
@@ -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())
}
+52
View File
@@ -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())
}
+63
View File
@@ -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
}
}
}
+33
View File
@@ -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]
}
+33
View File
@@ -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)
}