1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00
v/vlib/crypto/des/block.v
2022-01-07 13:51:37 +02:00

190 lines
5.5 KiB
V

// 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)
}