mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
crypto: add a crypto.des module (#13065)
This commit is contained in:
parent
7276705684
commit
2b42ea9883
121
vlib/crypto/cipher/cbc.v
Normal file
121
vlib/crypto/cipher/cbc.v
Normal file
@ -0,0 +1,121 @@
|
||||
// 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 []byte
|
||||
tmp []byte
|
||||
}
|
||||
|
||||
// internal
|
||||
fn new_des_cbc(b Block, iv []byte) Cbc {
|
||||
return Cbc{
|
||||
b: b
|
||||
block_size: b.block_size
|
||||
iv: iv.clone()
|
||||
tmp: []byte{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 []byte) 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 (x &Cbc) encrypt_blocks(mut dst_ []byte, src_ []byte) {
|
||||
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(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 []byte, src []byte) {
|
||||
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(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 (x &Cbc) set_iv(iv []byte) {
|
||||
if iv.len != x.iv.len {
|
||||
panic('cipher: incorrect length IV')
|
||||
}
|
||||
copy(x.iv, iv)
|
||||
}
|
55
vlib/crypto/cipher/cipher.v
Normal file
55
vlib/crypto/cipher/cipher.v
Normal file
@ -0,0 +1,55 @@
|
||||
// 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.
|
||||
interface Block {
|
||||
block_size int // block_size returns the cipher's block size.
|
||||
encrypt(mut dst []byte, src []byte) // Encrypt encrypts the first block in src into dst.
|
||||
// Dst and src must overlap entirely or not at all.
|
||||
decrypt(mut dst []byte, src []byte) // 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.
|
||||
interface Stream {
|
||||
// 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 []byte, src []byte)
|
||||
}
|
||||
|
||||
// A BlockMode represents a block cipher running in a block-based mode (CBC,
|
||||
// ECB etc).
|
||||
interface BlockMode {
|
||||
block_size int // block_size returns the mode's block size.
|
||||
crypt_blocks(mut dst []byte, src []byte) // 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.
|
||||
}
|
||||
|
||||
// Utility routines
|
||||
|
||||
// fn dup(p []byte) []byte {
|
||||
// q := make([]byte, p.len)
|
||||
// copy(q, p)
|
||||
// return q
|
||||
// }
|
54
vlib/crypto/cipher/des_cbc_test.v
Normal file
54
vlib/crypto/cipher/des_cbc_test.v
Normal file
@ -0,0 +1,54 @@
|
||||
import crypto.des
|
||||
import crypto.cipher
|
||||
|
||||
const (
|
||||
key = '123456789012345678901234'.bytes()
|
||||
iv = 'abcdegfh'.bytes()
|
||||
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 []byte, key []byte, iv []byte) {
|
||||
block := des.new_cipher(key)
|
||||
mode := cipher.new_cbc(block, iv)
|
||||
mode.encrypt_blocks(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn des_cbc_de(mut src []byte, key []byte, iv []byte) {
|
||||
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 []byte, key []byte, iv []byte) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mode := cipher.new_cbc(block, iv)
|
||||
mode.encrypt_blocks(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_cbc_de(mut src []byte, key []byte, iv []byte) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
mut mode := cipher.new_cbc(block, iv)
|
||||
mode.decrypt_blocks(mut src, src.clone())
|
||||
}
|
189
vlib/crypto/des/block.v
Normal file
189
vlib/crypto/des/block.v
Normal file
@ -0,0 +1,189 @@
|
||||
// The source code refers to the go standard library, which can be merged with AES later
|
||||
|
||||
module des
|
||||
|
||||
import encoding.binary
|
||||
|
||||
fn feistel(ll u32, rr u32, k0 u64, k1 u64) (u32, u32) {
|
||||
mut l := ll
|
||||
mut r := rr
|
||||
mut t := r ^ u32(k0 >> 32)
|
||||
|
||||
l ^= feistel_box[7][t & 0x3f] ^ feistel_box[5][(t >> 8) & 0x3f] ^ feistel_box[3][(t >> 16) & 0x3f] ^ feistel_box[1][(t >> 24) & 0x3f]
|
||||
|
||||
t = ((r << 28) | (r >> 4)) ^ u32(k0)
|
||||
l ^= feistel_box[6][t & 0x3f] ^ feistel_box[4][(t >> 8) & 0x3f] ^ feistel_box[2][(t >> 16) & 0x3f] ^ feistel_box[0][(t >> 24) & 0x3f]
|
||||
|
||||
t = l ^ u32(k1 >> 32)
|
||||
r ^= feistel_box[7][t & 0x3f] ^ feistel_box[5][(t >> 8) & 0x3f] ^ feistel_box[3][(t >> 16) & 0x3f] ^ feistel_box[1][(t >> 24) & 0x3f]
|
||||
|
||||
t = ((l << 28) | (l >> 4)) ^ u32(k1)
|
||||
r ^= feistel_box[6][t & 0x3f] ^ feistel_box[4][(t >> 8) & 0x3f] ^ feistel_box[2][(t >> 16) & 0x3f] ^ feistel_box[0][(t >> 24) & 0x3f]
|
||||
|
||||
return l, r
|
||||
}
|
||||
|
||||
fn crypt_block(subkeys []u64, mut dst []byte, src []byte, decrypt bool) {
|
||||
mut b := binary.big_endian_u64(src)
|
||||
b = permute_initial_block(b)
|
||||
|
||||
mut left, mut right := u32(b >> 32), u32(b)
|
||||
|
||||
left = (left << 1) | (left >> 31)
|
||||
right = (right << 1) | (right >> 31)
|
||||
|
||||
if decrypt {
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, subkeys[15 - 2 * i], subkeys[15 - (2 * i + 1)])
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, subkeys[2 * i], subkeys[2 * i + 1])
|
||||
}
|
||||
}
|
||||
|
||||
left = (left << 31) | (left >> 1)
|
||||
right = (right << 31) | (right >> 1)
|
||||
|
||||
// switch left & right and perform final permutation
|
||||
pre_output := (u64(right) << 32) | u64(left)
|
||||
binary.big_endian_put_u64(mut dst, permute_final_block(pre_output))
|
||||
}
|
||||
|
||||
// Encrypt one block from src into dst, using the subkeys.
|
||||
pub fn encrypt_block(subkeys []u64, mut dst []byte, src []byte) {
|
||||
crypt_block(subkeys, mut dst, src, false)
|
||||
}
|
||||
|
||||
// Decrypt one block from src into dst, using the subkeys.
|
||||
fn decrypt_block(subkeys []u64, mut dst []byte, src []byte) {
|
||||
crypt_block(subkeys, mut dst, src, true)
|
||||
}
|
||||
|
||||
// general purpose function to perform DES block permutations
|
||||
fn permute_block(src u64, permutation []byte) u64 {
|
||||
mut block := u64(0)
|
||||
for position, n in permutation {
|
||||
bit := (src >> u64(u8(n))) & 1
|
||||
block |= bit << u64((permutation.len - 1) - position)
|
||||
}
|
||||
return block
|
||||
}
|
||||
|
||||
// permuteInitial_block is equivalent to the permutation defined
|
||||
// by initialPermutation.
|
||||
fn permute_initial_block(b u64) u64 {
|
||||
// block = b7 b6 b5 b4 b3 b2 b1 b0 (8 bytes)
|
||||
mut block := b
|
||||
mut b1 := block >> 48
|
||||
mut b2 := block << 48
|
||||
block ^= b1 ^ b2 ^ b1 << 48 ^ b2 >> 48
|
||||
|
||||
// block = b1 b0 b5 b4 b3 b2 b7 b6
|
||||
b1 = block >> 32 & 0xff00ff
|
||||
b2 = (block & 0xff00ff00)
|
||||
block ^= b1 << 32 ^ b2 ^ b1 << 8 ^ b2 << 24 // exchange b0 b4 with b3 b7
|
||||
|
||||
// block is now b1 b3 b5 b7 b0 b2 b4 b6, the permutation:
|
||||
// ... 8
|
||||
// ... 24
|
||||
// ... 40
|
||||
// ... 56
|
||||
// 7 6 5 4 3 2 1 0
|
||||
// 23 22 21 20 19 18 17 16
|
||||
// ... 32
|
||||
// ... 48
|
||||
|
||||
// exchange 4,5,6,7 with 32,33,34,35 etc.
|
||||
b1 = block & 0x0f0f00000f0f0000
|
||||
b2 = block & 0x0000f0f00000f0f0
|
||||
block ^= b1 ^ b2 ^ b1 >> 12 ^ b2 << 12
|
||||
|
||||
// block is the permutation:
|
||||
//
|
||||
// [+8] [+40]
|
||||
//
|
||||
// 7 6 5 4
|
||||
// 23 22 21 20
|
||||
// 3 2 1 0
|
||||
// 19 18 17 16 [+32]
|
||||
|
||||
// exchange 0,1,4,5 with 18,19,22,23
|
||||
b1 = block & 0x3300330033003300
|
||||
b2 = block & 0x00cc00cc00cc00cc
|
||||
block ^= b1 ^ b2 ^ b1 >> 6 ^ b2 << 6
|
||||
|
||||
// block is the permutation:
|
||||
// 15 14
|
||||
// 13 12
|
||||
// 11 10
|
||||
// 9 8
|
||||
// 7 6
|
||||
// 5 4
|
||||
// 3 2
|
||||
// 1 0 [+16] [+32] [+64]
|
||||
|
||||
// exchange 0,2,4,6 with 9,11,13,15:
|
||||
b1 = block & 0xaaaaaaaa55555555
|
||||
block ^= b1 ^ b1 >> 33 ^ b1 << 33
|
||||
|
||||
// block is the permutation:
|
||||
// 6 14 22 30 38 46 54 62
|
||||
// 4 12 20 28 36 44 52 60
|
||||
// 2 10 18 26 34 42 50 58
|
||||
// 0 8 16 24 32 40 48 56
|
||||
// 7 15 23 31 39 47 55 63
|
||||
// 5 13 21 29 37 45 53 61
|
||||
// 3 11 19 27 35 43 51 59
|
||||
// 1 9 17 25 33 41 49 57
|
||||
return block
|
||||
}
|
||||
|
||||
// permuteInitial_block is equivalent to the permutation defined
|
||||
// by finalPermutation.
|
||||
fn permute_final_block(b u64) u64 {
|
||||
// Perform the same bit exchanges as permuteInitial_block
|
||||
// but in reverse order.
|
||||
mut block := b
|
||||
mut b1 := block & 0xaaaaaaaa55555555
|
||||
block ^= b1 ^ b1 >> 33 ^ b1 << 33
|
||||
|
||||
b1 = block & 0x3300330033003300
|
||||
mut b2 := block & 0x00cc00cc00cc00cc
|
||||
block ^= b1 ^ b2 ^ b1 >> 6 ^ b2 << 6
|
||||
|
||||
b1 = block & 0x0f0f00000f0f0000
|
||||
b2 = block & 0x0000f0f00000f0f0
|
||||
block ^= b1 ^ b2 ^ b1 >> 12 ^ b2 << 12
|
||||
|
||||
b1 = block >> 32 & 0xff00ff
|
||||
b2 = (block & 0xff00ff00)
|
||||
block ^= b1 << 32 ^ b2 ^ b1 << 8 ^ b2 << 24
|
||||
|
||||
b1 = block >> 48
|
||||
b2 = block << 48
|
||||
block ^= b1 ^ b2 ^ b1 << 48 ^ b2 >> 48
|
||||
return block
|
||||
}
|
||||
|
||||
// creates 16 28-bit blocks rotated according
|
||||
// to the rotation schedule
|
||||
fn ks_rotate(ain u32) []u32 {
|
||||
mut out := []u32{len: 16}
|
||||
mut last := ain
|
||||
for i := 0; i < 16; i++ {
|
||||
// 28-bit circular left shift
|
||||
left := (last << (4 + ks_rotations[i])) >> 4
|
||||
right := (last << 4) >> (32 - ks_rotations[i])
|
||||
out[i] = left | right
|
||||
last = out[i]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Expand 48-bit input to 64-bit, with each 6-bit block padded by extra two bits at the top.
|
||||
// By doing so, we can have the input blocks (four bits each), and the key blocks (six bits each) well-aligned without
|
||||
// extra shifts/rotations for alignments.
|
||||
fn unpack(x u64) u64 {
|
||||
return ((x >> (6 * 1)) & 0xff) << (8 * 0) | ((x >> (6 * 3)) & 0xff) << (8 * 1) | ((x >> (6 * 5)) & 0xff) << (8 * 2) | ((x >> (6 * 7)) & 0xff) << (8 * 3) | ((x >> (6 * 0)) & 0xff) << (8 * 4) | ((x >> (6 * 2)) & 0xff) << (8 * 5) | ((x >> (6 * 4)) & 0xff) << (8 * 6) | ((x >> (6 * 6)) & 0xff) << (8 * 7)
|
||||
}
|
154
vlib/crypto/des/const.v
Normal file
154
vlib/crypto/des/const.v
Normal file
@ -0,0 +1,154 @@
|
||||
// The source code refers to the go standard library, which can be merged with AES later
|
||||
|
||||
// Package des implements the Data Encryption Standard (DES) and the
|
||||
// Triple Data Encryption Algorithm (TDEA) as defined
|
||||
// in U.S. Federal Information Processing Standards Publication 46-3.
|
||||
//
|
||||
// DES is cryptographically broken and should not be used for secure
|
||||
// applications.
|
||||
|
||||
module des
|
||||
|
||||
// Used to perform an initial permutation of a 64-bit input block.
|
||||
// const initial_permutation = [byte(6), 14, 22, 30, 38, 46, 54, 62, 4, 12, 20, 28, 36, 44, 52, 60,
|
||||
// 2, 10, 18, 26, 34, 42, 50, 58, 0, 8, 16, 24, 32, 40, 48, 56, 7, 15, 23, 31, 39, 47, 55, 63,
|
||||
// 5, 13, 21, 29, 37, 45, 53, 61, 3, 11, 19, 27, 35, 43, 51, 59, 1, 9, 17, 25, 33, 41, 49, 57]
|
||||
|
||||
// // Used to perform a final permutation of a 4-bit preoutput block. This is the
|
||||
// // inverse of initialPermutation
|
||||
// const final_permutation = [byte(24), 56, 16, 48, 8, 40, 0, 32, 25, 57, 17, 49, 9, 41, 1, 33, 26,
|
||||
// 58, 18, 50, 10, 42, 2, 34, 27, 59, 19, 51, 11, 43, 3, 35, 28, 60, 20, 52, 12, 44, 4, 36, 29,
|
||||
// 61, 21, 53, 13, 45, 5, 37, 30, 62, 22, 54, 14, 46, 6, 38, 31, 63, 23, 55, 15, 47, 7, 39]
|
||||
|
||||
// // Used to expand an input block of 32 bits, producing an output block of 48
|
||||
// // bits.
|
||||
// const expansion_function = [byte(0), 31, 30, 29, 28, 27, 28, 27, 26, 25, 24, 23, 24, 23, 22, 21,
|
||||
// 20, 19, 20, 19, 18, 17, 16, 15, 16, 15, 14, 13, 12, 11, 12, 11, 10, 9, 8, 7, 8, 7, 6, 5, 4,
|
||||
// 3, 4, 3, 2, 1, 0, 31]
|
||||
|
||||
// // Yields a 32-bit output from a 32-bit input
|
||||
// const permutation_function = [byte(16), 25, 12, 11, 3, 20, 4, 15, 31, 17, 9, 6, 27, 14, 1, 22,
|
||||
// 30, 24, 8, 18, 0, 5, 29, 23, 13, 19, 2, 26, 10, 21, 28, 7]
|
||||
|
||||
// Used in the key schedule to select 56 bits
|
||||
// from a 64-bit input.
|
||||
const permuted_choice1 = [byte(7), 15, 23, 31, 39, 47, 55, 63, 6, 14, 22, 30, 38, 46, 54, 62, 5,
|
||||
13, 21, 29, 37, 45, 53, 61, 4, 12, 20, 28, 1, 9, 17, 25, 33, 41, 49, 57, 2, 10, 18, 26, 34,
|
||||
42, 50, 58, 3, 11, 19, 27, 35, 43, 51, 59, 36, 44, 52, 60]
|
||||
|
||||
// Used in the key schedule to produce each subkey by selecting 48 bits from
|
||||
// the 56-bit input
|
||||
const permuted_choice2 = [byte(42), 39, 45, 32, 55, 51, 53, 28, 41, 50, 35, 46, 33, 37, 44, 52,
|
||||
30, 48, 40, 49, 29, 36, 43, 54, 15, 4, 25, 19, 9, 1, 26, 16, 5, 11, 23, 8, 12, 7, 17, 0, 22,
|
||||
3, 10, 14, 6, 20, 27, 24]
|
||||
|
||||
// 8 S-boxes composed of 4 rows and 16 columns
|
||||
// Used in the DES cipher function
|
||||
// const s_boxes = [
|
||||
// [
|
||||
// [u8(14), 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],
|
||||
// [u8(0), 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],
|
||||
// [u8(4), 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],
|
||||
// [u8(15), 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],
|
||||
// ],
|
||||
// [
|
||||
// [u8(15), 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10],
|
||||
// [u8(3), 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5],
|
||||
// [u8(0), 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15],
|
||||
// [u8(13), 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],
|
||||
// ],
|
||||
// [
|
||||
// [u8(10), 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8],
|
||||
// [u8(13), 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1],
|
||||
// [u8(13), 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7],
|
||||
// [u8(1), 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],
|
||||
// ],
|
||||
// [
|
||||
// [u8(7), 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15],
|
||||
// [u8(13), 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9],
|
||||
// [u8(10), 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4],
|
||||
// [u8(3), 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],
|
||||
// ],
|
||||
// [
|
||||
// [u8(2), 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9],
|
||||
// [u8(14), 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6],
|
||||
// [u8(4), 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14],
|
||||
// [u8(11), 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],
|
||||
// ],
|
||||
// [
|
||||
// [u8(12), 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11],
|
||||
// [u8(10), 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8],
|
||||
// [u8(9), 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6],
|
||||
// [u8(4), 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],
|
||||
// ],
|
||||
// [
|
||||
// [u8(4), 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1],
|
||||
// [u8(13), 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6],
|
||||
// [u8(1), 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2],
|
||||
// [u8(6), 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],
|
||||
// ],
|
||||
// [
|
||||
// [u8(13), 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7],
|
||||
// [u8(1), 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2],
|
||||
// [u8(7), 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8],
|
||||
// [u8(2), 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],
|
||||
// ],
|
||||
// ]
|
||||
|
||||
const feistel_box = [
|
||||
[u32(16843776), 0, 65536, 16843780, 16842756, 66564, 4, 65536, 1024, 16843776, 16843780, 1024,
|
||||
16778244, 16842756, 16777216, 4, 1028, 16778240, 16778240, 66560, 66560, 16842752, 16842752,
|
||||
16778244, 65540, 16777220, 16777220, 65540, 0, 1028, 66564, 16777216, 65536, 16843780,
|
||||
4, 16842752, 16843776, 16777216, 16777216, 1024, 16842756, 65536, 66560, 16777220, 1024,
|
||||
4, 16778244, 66564, 16843780, 65540, 16842752, 16778244, 16777220, 1028, 66564, 16843776,
|
||||
1028, 16778240, 16778240, 0, 65540, 66560, 0, 16842756],
|
||||
[u32(2148565024), 2147516416, 32768, 1081376, 1048576, 32, 2148532256, 2147516448, 2147483680,
|
||||
2148565024, 2148564992, 2147483648, 2147516416, 1048576, 32, 2148532256, 1081344, 1048608,
|
||||
2147516448, 0, 2147483648, 32768, 1081376, 2148532224, 1048608, 2147483680, 0, 1081344,
|
||||
32800, 2148564992, 2148532224, 32800, 0, 1081376, 2148532256, 1048576, 2147516448, 2148532224,
|
||||
2148564992, 32768, 2148532224, 2147516416, 32, 2148565024, 1081376, 32, 32768, 2147483648,
|
||||
32800, 2148564992, 1048576, 2147483680, 1048608, 2147516448, 2147483680, 1048608, 1081344,
|
||||
0, 2147516416, 32800, 2147483648, 2148532256, 2148565024, 1081344],
|
||||
[u32(520), 134349312, 0, 134348808, 134218240, 0, 131592, 134218240, 131080, 134217736, 134217736,
|
||||
131072, 134349320, 131080, 134348800, 520, 134217728, 8, 134349312, 512, 131584, 134348800,
|
||||
134348808, 131592, 134218248, 131584, 131072, 134218248, 8, 134349320, 512, 134217728,
|
||||
134349312, 134217728, 131080, 520, 131072, 134349312, 134218240, 0, 512, 131080, 134349320,
|
||||
134218240, 134217736, 512, 0, 134348808, 134218248, 131072, 134217728, 134349320, 8, 131592,
|
||||
131584, 134217736, 134348800, 134218248, 520, 134348800, 131592, 8, 134348808, 131584],
|
||||
[u32(8396801), 8321, 8321, 128, 8396928, 8388737, 8388609, 8193, 0, 8396800, 8396800, 8396929,
|
||||
129, 0, 8388736, 8388609, 1, 8192, 8388608, 8396801, 128, 8388608, 8193, 8320, 8388737,
|
||||
1, 8320, 8388736, 8192, 8396928, 8396929, 129, 8388736, 8388609, 8396800, 8396929, 129,
|
||||
0, 0, 8396800, 8320, 8388736, 8388737, 1, 8396801, 8321, 8321, 128, 8396929, 129, 1, 8192,
|
||||
8388609, 8193, 8396928, 8388737, 8193, 8320, 8388608, 8396801, 128, 8388608, 8192, 8396928],
|
||||
[u32(256), 34078976, 34078720, 1107296512, 524288, 256, 1073741824, 34078720, 1074266368, 524288,
|
||||
33554688, 1074266368, 1107296512, 1107820544, 524544, 1073741824, 33554432, 1074266112,
|
||||
1074266112, 0, 1073742080, 1107820800, 1107820800, 33554688, 1107820544, 1073742080, 0,
|
||||
1107296256, 34078976, 33554432, 1107296256, 524544, 524288, 1107296512, 256, 33554432,
|
||||
1073741824, 34078720, 1107296512, 1074266368, 33554688, 1073741824, 1107820544, 34078976,
|
||||
1074266368, 256, 33554432, 1107820544, 1107820800, 524544, 1107296256, 1107820800, 34078720,
|
||||
0, 1074266112, 1107296256, 524544, 33554688, 1073742080, 524288, 0, 1074266112, 34078976,
|
||||
1073742080],
|
||||
[u32(536870928), 541065216, 16384, 541081616, 541065216, 16, 541081616, 4194304, 536887296,
|
||||
4210704, 4194304, 536870928, 4194320, 536887296, 536870912, 16400, 0, 4194320, 536887312,
|
||||
16384, 4210688, 536887312, 16, 541065232, 541065232, 0, 4210704, 541081600, 16400, 4210688,
|
||||
541081600, 536870912, 536887296, 16, 541065232, 4210688, 541081616, 4194304, 16400, 536870928,
|
||||
4194304, 536887296, 536870912, 16400, 536870928, 541081616, 4210688, 541065216, 4210704,
|
||||
541081600, 0, 541065232, 16, 16384, 541065216, 4210704, 16384, 4194320, 536887312, 0,
|
||||
541081600, 536870912, 4194320, 536887312],
|
||||
[u32(2097152), 69206018, 67110914, 0, 2048, 67110914, 2099202, 69208064, 69208066, 2097152,
|
||||
0, 67108866, 2, 67108864, 69206018, 2050, 67110912, 2099202, 2097154, 67110912, 67108866,
|
||||
69206016, 69208064, 2097154, 69206016, 2048, 2050, 69208066, 2099200, 2, 67108864, 2099200,
|
||||
67108864, 2099200, 2097152, 67110914, 67110914, 69206018, 69206018, 2, 2097154, 67108864,
|
||||
67110912, 2097152, 69208064, 2050, 2099202, 69208064, 2050, 67108866, 69208066, 69206016,
|
||||
2099200, 0, 2, 69208066, 0, 2099202, 69206016, 2048, 67108866, 67110912, 2048, 2097154],
|
||||
[u32(268439616), 4096, 262144, 268701760, 268435456, 268439616, 64, 268435456, 262208, 268697600,
|
||||
268701760, 266240, 268701696, 266304, 4096, 64, 268697600, 268435520, 268439552, 4160,
|
||||
266240, 262208, 268697664, 268701696, 4160, 0, 0, 268697664, 268435520, 268439552, 266304,
|
||||
262144, 266304, 262144, 268701696, 4096, 64, 268697664, 4096, 266304, 268439552, 64,
|
||||
268435520, 268697600, 268697664, 268435456, 262144, 268439616, 0, 268701760, 262208,
|
||||
268435520, 268697600, 268439552, 268439616, 0, 268701760, 266240, 266240, 4160, 4160, 262208,
|
||||
268435456, 268701696],
|
||||
]
|
||||
|
||||
// Size of left rotation per round in each half of the key schedule
|
||||
const ks_rotations = [u8(1), 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
|
169
vlib/crypto/des/des.v
Normal file
169
vlib/crypto/des/des.v
Normal file
@ -0,0 +1,169 @@
|
||||
// The source code refers to the go standard library
|
||||
|
||||
module des
|
||||
|
||||
import crypto.cipher
|
||||
import crypto.internal.subtle
|
||||
import encoding.binary
|
||||
|
||||
const block_size = 8
|
||||
|
||||
// A tripleDesCipher is an instance of TripleDES encryption.
|
||||
struct TripleDesCipher {
|
||||
block_size int = des.block_size
|
||||
mut:
|
||||
cipher1 DesCipher
|
||||
cipher2 DesCipher
|
||||
cipher3 DesCipher
|
||||
}
|
||||
|
||||
// DesCipher is an instance of DES encryption.
|
||||
struct DesCipher {
|
||||
block_size int = des.block_size
|
||||
mut:
|
||||
subkeys [16]u64
|
||||
}
|
||||
|
||||
// NewCipher creates and returns a new cipher.Block.
|
||||
pub fn new_cipher(key []byte) cipher.Block {
|
||||
if key.len != 8 {
|
||||
panic('crypto.aes: invalid key size')
|
||||
}
|
||||
|
||||
mut c := DesCipher{}
|
||||
c.generate_subkeys(key)
|
||||
return c
|
||||
}
|
||||
|
||||
// creates 16 56-bit subkeys from the original key
|
||||
fn (mut c DesCipher) generate_subkeys(key_bytes []byte) {
|
||||
// feistel_box_once.do(initFeistel_box)
|
||||
|
||||
// apply PC1 permutation to key
|
||||
key := binary.big_endian_u64(key_bytes)
|
||||
permuted_key := permute_block(key, permuted_choice1[..])
|
||||
|
||||
// rotate halves of permuted key according to the rotation schedule
|
||||
left_rotations := ks_rotate(u32(permuted_key >> 28))
|
||||
right_rotations := ks_rotate(u32(permuted_key << 4) >> 4)
|
||||
|
||||
// generate subkeys
|
||||
for i := 0; i < 16; i++ {
|
||||
// combine halves to form 56-bit input to PC2
|
||||
pc2_input := u64(left_rotations[i]) << 28 | u64(right_rotations[i])
|
||||
// apply PC2 permutation to 7 byte input
|
||||
c.subkeys[i] = unpack(permute_block(pc2_input, permuted_choice2[..]))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c &DesCipher) encrypt(mut dst []byte, src []byte) {
|
||||
if src.len < des.block_size {
|
||||
panic('crypto/des: input not full block')
|
||||
}
|
||||
if dst.len < des.block_size {
|
||||
panic('crypto/des: output not full block')
|
||||
}
|
||||
if subtle.inexact_overlap(dst[..des.block_size], src[..des.block_size]) {
|
||||
panic('crypto/des: invalid buffer overlap')
|
||||
}
|
||||
encrypt_block(c.subkeys[..], mut dst, src)
|
||||
}
|
||||
|
||||
pub fn (c &DesCipher) decrypt(mut dst []byte, src []byte) {
|
||||
if src.len < des.block_size {
|
||||
panic('crypto/des: input not full block')
|
||||
}
|
||||
if dst.len < des.block_size {
|
||||
panic('crypto/des: output not full block')
|
||||
}
|
||||
if subtle.inexact_overlap(dst[..des.block_size], src[..des.block_size]) {
|
||||
panic('crypto/des: invalid buffer overlap')
|
||||
}
|
||||
decrypt_block(c.subkeys[..], mut dst, src)
|
||||
}
|
||||
|
||||
// NewTripleDesCipher creates and returns a new cipher.Block.
|
||||
pub fn new_triple_des_cipher(key []byte) cipher.Block {
|
||||
if key.len != 24 {
|
||||
panic('crypto.des: invalid key size')
|
||||
}
|
||||
mut c := TripleDesCipher{}
|
||||
c.cipher1.generate_subkeys(key[..8])
|
||||
c.cipher2.generate_subkeys(key[8..16])
|
||||
c.cipher3.generate_subkeys(key[16..])
|
||||
return c
|
||||
}
|
||||
|
||||
pub fn (c &TripleDesCipher) encrypt(mut dst []byte, src []byte) {
|
||||
if src.len < des.block_size {
|
||||
panic('crypto/des: input not full block')
|
||||
}
|
||||
if dst.len < des.block_size {
|
||||
panic('crypto/des: output not full block')
|
||||
}
|
||||
if subtle.inexact_overlap(dst[..des.block_size], src[..des.block_size]) {
|
||||
panic('crypto/des: invalid buffer overlap')
|
||||
}
|
||||
|
||||
mut b := binary.big_endian_u64(src)
|
||||
b = permute_initial_block(b)
|
||||
mut left, mut right := u32(b >> 32), u32(b)
|
||||
|
||||
left = (left << 1) | (left >> 31)
|
||||
right = (right << 1) | (right >> 31)
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, c.cipher1.subkeys[2 * i], c.cipher1.subkeys[2 * i + 1])
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
right, left = feistel(right, left, c.cipher2.subkeys[15 - 2 * i], c.cipher2.subkeys[15 - (
|
||||
2 * i + 1)])
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, c.cipher3.subkeys[2 * i], c.cipher3.subkeys[2 * i + 1])
|
||||
}
|
||||
|
||||
left = (left << 31) | (left >> 1)
|
||||
right = (right << 31) | (right >> 1)
|
||||
|
||||
pre_output := (u64(right) << 32) | u64(left)
|
||||
binary.big_endian_put_u64(mut dst, permute_final_block(pre_output))
|
||||
}
|
||||
|
||||
pub fn (c &TripleDesCipher) decrypt(mut dst []byte, src []byte) {
|
||||
if src.len < des.block_size {
|
||||
panic('crypto/des: input not full block')
|
||||
}
|
||||
if dst.len < des.block_size {
|
||||
panic('crypto/des: output not full block')
|
||||
}
|
||||
if subtle.inexact_overlap(dst[..des.block_size], src[..des.block_size]) {
|
||||
panic('crypto/des: invalid buffer overlap')
|
||||
}
|
||||
|
||||
mut b := binary.big_endian_u64(src)
|
||||
b = permute_initial_block(b)
|
||||
|
||||
mut left, mut right := u32(b >> 32), u32(b)
|
||||
|
||||
left = (left << 1) | (left >> 31)
|
||||
right = (right << 1) | (right >> 31)
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, c.cipher3.subkeys[15 - 2 * i], c.cipher3.subkeys[15 - (
|
||||
2 * i + 1)])
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
right, left = feistel(right, left, c.cipher2.subkeys[2 * i], c.cipher2.subkeys[2 * i + 1])
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, c.cipher1.subkeys[15 - 2 * i], c.cipher1.subkeys[15 - (
|
||||
2 * i + 1)])
|
||||
}
|
||||
|
||||
left = (left << 31) | (left >> 1)
|
||||
right = (right << 31) | (right >> 1)
|
||||
|
||||
pre_output := (u64(right) << 32) | u64(left)
|
||||
binary.big_endian_put_u64(mut dst, permute_final_block(pre_output))
|
||||
}
|
51
vlib/crypto/des/des_test.v
Normal file
51
vlib/crypto/des/des_test.v
Normal file
@ -0,0 +1,51 @@
|
||||
import crypto.des
|
||||
|
||||
const (
|
||||
key = '123456789012345678901234'.bytes()
|
||||
iv = 'abcdegfh'.bytes()
|
||||
str = 'aaaaaaaa'
|
||||
)
|
||||
|
||||
fn test_triple_des() {
|
||||
mut src := str.bytes()
|
||||
|
||||
triple_des_en(mut src, key, iv)
|
||||
assert src.hex() == '45902cf00aa1df46'
|
||||
|
||||
triple_des_de(mut src, key, iv)
|
||||
assert src.bytestr() == str
|
||||
println('test_triple_des ok')
|
||||
}
|
||||
|
||||
fn test_des() {
|
||||
mut src := str.bytes()
|
||||
|
||||
des_en(mut src, key[..8], iv)
|
||||
assert src.hex() == '72dca13c37223cf0'
|
||||
|
||||
des_de(mut src, key[..8], iv)
|
||||
assert src.bytestr() == str
|
||||
|
||||
println('test_des ok')
|
||||
}
|
||||
|
||||
fn des_en(mut src []byte, key []byte, iv []byte) {
|
||||
block := des.new_cipher(key)
|
||||
block.encrypt(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn des_de(mut src []byte, key []byte, iv []byte) {
|
||||
block := des.new_cipher(key)
|
||||
block.decrypt(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_en(mut src []byte, key []byte, iv []byte) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
block.encrypt(mut src, src.clone())
|
||||
}
|
||||
|
||||
fn triple_des_de(mut src []byte, key []byte, iv []byte) {
|
||||
block := des.new_triple_des_cipher(key)
|
||||
inbuf := src.clone()
|
||||
block.decrypt(mut src, inbuf)
|
||||
}
|
Loading…
Reference in New Issue
Block a user