Created
November 25, 2018 14:54
-
-
Save konradmb/26342f35727730ca835144e4fae6ddbb to your computer and use it in GitHub Desktop.
Nim DES
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import strutils | |
import sequtils | |
import bitops | |
import os | |
import des_utils | |
type CDTuple = array[17,tuple[c:BitArray,d:BitArray]] | |
type LRTuple = array[17,tuple[l: bin32,r: bin32]] | |
import macros | |
proc genCDArray(c0:BitArray, d0:BitArray): array[17,tuple[c:BitArray,d:BitArray]] = | |
for i in 0..16: | |
case i: | |
of 0: | |
result[i] = (c0,d0) | |
of 1..2, 9, 16: | |
result[i] = (result[i-1].c shl 1, result[i-1].d shl 1) | |
of 3..8, 10..15: | |
result[i] = (result[i-1].c shl 2, result[i-1].d shl 2) | |
else: | |
echo "AAAA!!!!!11111" | |
# echo result[0].d | |
# echo result[16].d | |
func permutate(key: bin64, table: openarray[int]): bin64 = | |
var resultIndex = 0 | |
for i in table: | |
result[resultIndex] = key[i] | |
inc(resultIndex) | |
func permutateSB(key: bin32, table: openarray[int]): bin32 = | |
var resultIndex = 0 | |
for i in table: | |
result[31-resultIndex] = key[31-i] | |
inc(resultIndex) | |
func permutate(key: BitArray, table: openarray[int], size: int): BitArray = | |
result = newBitArray(size) | |
var resultIndex = 0 | |
for i in table: | |
result[resultIndex] = key[i] | |
inc(resultIndex) | |
func permutate(key: bin64, table: openarray[int], size: int): BitArray = | |
result = newBitArray(size) | |
var resultIndex = 0 | |
for i in table: | |
result[resultIndex] = key[63-i] | |
inc(resultIndex) | |
func permutate(key: bin32, table: openarray[int], size: int): BitArray = | |
result = newBitArray(size) | |
var resultIndex = 0 | |
for i in table: | |
result[resultIndex] = key[31-i] | |
inc(resultIndex) | |
func permutateSubkeys(keys: CDTuple): array[17,BitArray] = | |
## Returns 17 keys in 48 bit BitArray | |
var resultIndex = 0 | |
for i in keys: | |
var key = concat(i.c, i.d) | |
# debugEcho key | |
# debug key | |
result[resultIndex] = permutate(key, PC2,48) | |
inc(resultIndex) | |
func applyS(bee: BitArray, sNum: int): BitArray = | |
# result = newBitArray(4) | |
var row = cast[int](parseBinInt($bee[0] & $bee[5])) | |
var col = cast[int](parseBinInt($bee[1] & $bee[2] & $bee[3] & $bee[4])) | |
# debug S[snum][row*16 + col].bin64.toBitArray(4) | |
result = S[snum][row*16 + col].bin64.toBitArray(4) | |
func functionF(r: bin32, k: BitArray): bin32 = | |
var r = permutate(r, E, 48) | |
var xored = k xor r | |
var bees: array[8,BitArray] | |
for i in mitems(bees): | |
i = newBitArray(6) | |
var xoredI, beesI1 = 0 | |
while xoredI < xored.high: | |
for beesI2 in 0..<6: | |
bees[beesI1][beesI2] = xored[xoredI] | |
inc(xoredI) | |
inc(beesI1) | |
var esBees: array[8, BitArray] | |
for i in 0..<8: | |
esBees[i] = applyS(bees[i], i) | |
var concatEsBees: seq[int] | |
for i in esBees: | |
for j in i: | |
concatEsBees.add(j) | |
# debugecho permutateSB(concatEsBees.toBitArray().toBin32(), P) | |
result = permutateSB(concatEsBees.toBitArray().toBin32(), P) | |
func permutateMessage(l0: bin32, r0:bin32, keys: array[17,BitArray]): bin64 = | |
var LRArray: LRTuple | |
LRArray[0] = (l0,r0) | |
for i in 1..16: | |
LRArray[i].l = LRArray[i-1].r | |
LRArray[i].r = LRArray[i-1].l xor functionF(LRArray[i-1].r, keys[i]) | |
var R16L16: bin64 = parseBinInt(toString(LRArray[16].r) & toString(LRArray[16].l)).bin64 | |
result = permutate(R16L16, IPminus1) | |
proc main(message: bin64, key: bin64, decrypt: bool): bin64 = | |
var permKey: BitArray = permutate(key,PC1,56) | |
var c0 = permKey.getLeftHalf() | |
var d0 = permKey.getRightHalf() | |
var CDArray = genCDArray(c0,d0) | |
# echo d0 | |
var KArray = permutateSubkeys(CDArray) # Tu ma być 16 kluczy, nie 17 | |
if decrypt: | |
var reversedKArray: array[17, BitArray] | |
for i in 1..<17: | |
reversedKArray[i] = KArray[17-i] | |
# echo reversedKArray[16-i] | |
KArray = reversedKArray | |
# echo KArray[16] | |
# KArray.apply((x) => echo x) | |
var permMessage = message.permutate(IP) | |
var l0 = permMessage.getLeftHalf() | |
var r0 = permMessage.getRightHalf() | |
result = permutateMessage(l0, r0, KArray) | |
proc encrypt(message: bin64, key: bin64): bin64 = | |
main(message, key, false) | |
proc decrypt(message: bin64, key: bin64): bin64 = | |
main(message, key, true) | |
var message: bin64 = 0x0123456789ABCDEF | |
var key: bin64 = 0x133457799BBCDFF1 | |
# for i in 0..100000: | |
# var crypt = main(message, key, false) | |
# decrypt = main(crypt, key, true) | |
# 0x0123456789ABCDEF | |
echo encrypt(0xDEADBEEFFACEFEED, 0x1122334455667788).toHex() | |
echo decrypt(0x612C9241E3C44392, 0x1122334455667788).toHex() | |
# echo decrypt.uint64.toHex() | |
assert main(0x0123456789ABCDEF, 0x133457799BBCDFF1, false).uint64.toHex() == "85E813540F0AB405" | |
assert main(0x85E813540F0AB405, 0x133457799BBCDFF1, true).uint64.toHex() == "0123456789ABCDEF" | |
# message = 0x0123456789ABCDEF | |
# key = 0x133457799BBCDFF1 | |
# assert message.int64 == 0b0000000100100011010001010110011110001001101010111100110111101111 | |
# assert key.int64 == 0b0001001100110100010101110111100110011011101111001101111111110001 | |
# assert permutate(key,PC1,56).getLeftHalf() == @[1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1] | |
# assert permutate(key,PC1,56).getRightHalf() == @[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import strutils | |
const PC1* = [ | |
56, 48, 40, 32, 24, 16, 8, | |
0, 57, 49, 41, 33, 25, 17, | |
9, 1, 58, 50, 42, 34, 26, | |
18, 10, 2, 59, 51, 43, 35, | |
62, 54, 46, 38, 30, 22, 14, | |
6, 61, 53, 45, 37, 29, 21, | |
13, 5, 60, 52, 44, 36, 28, | |
20, 12, 4, 27, 19, 11, 3 | |
] | |
const PC2* = [ | |
13, 16, 10, 23, 0, 4, | |
2, 27, 14, 5, 20, 9, | |
22, 18, 11, 3, 25, 7, | |
15, 6, 26, 19, 12, 1, | |
40, 51, 30, 36, 46, 54, | |
29, 39, 50, 44, 32, 47, | |
43, 48, 38, 55, 33, 52, | |
45, 41, 49, 35, 28, 31 | |
] | |
const IP* = [ | |
57, 49, 41, 33, 25, 17, | |
9, 1, 59, 51, 43, 35, | |
27, 19, 11, 3, 61, 53, | |
45, 37, 29, 21, 13, 5, | |
63, 55, 47, 39, 31, 23, | |
15, 7, 56, 48, 40, 32, | |
24, 16, 8, 0, 58, 50, | |
42, 34, 26, 18, 10, 2, | |
60, 52, 44, 36, 28, 20, | |
12, 4, 62, 54, 46, 38, | |
30, 22, 14, 6 | |
] | |
const IPminus1* = [ | |
39, 7, 47, 15, 55, 23, 63, 31, | |
38, 6, 46, 14, 54, 22, 62, 30, | |
37, 5, 45, 13, 53, 21, 61, 29, | |
36, 4, 44, 12, 52, 20, 60, 28, | |
35, 3, 43, 11, 51, 19, 59, 27, | |
34, 2, 42, 10, 50, 18, 58, 26, | |
33, 1, 41, 9, 49, 17, 57, 25, | |
32, 0, 40, 8, 48, 16, 56, 24 | |
] | |
const E* = [ | |
31, 0, 1, 2, 3, 4, | |
3, 4, 5, 6, 7, 8, | |
7, 8, 9, 10, 11, 12, | |
11, 12, 13, 14, 15, 16, | |
15, 16, 17, 18, 19, 20, | |
19, 20, 21, 22, 23, 24, | |
23, 24, 25, 26, 27, 28, | |
27, 28, 29, 30, 31, 0 | |
] | |
const P* = [ | |
15, 6, 19, 20, | |
28, 11, 27, 16, | |
0, 14, 22, 25, | |
4, 17, 30, 9, | |
1, 7, 23, 13, | |
31, 26, 2, 8, | |
18, 12, 29, 5, | |
21, 10, 3, 24 | |
] | |
const S* = [ | |
[ | |
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, | |
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, | |
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, | |
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 | |
], | |
[ | |
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, | |
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, | |
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, | |
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 | |
], | |
[ | |
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, | |
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, | |
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, | |
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 | |
], | |
[ | |
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, | |
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, | |
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, | |
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 | |
], | |
[ | |
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, | |
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, | |
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, | |
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 | |
], | |
[ | |
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, | |
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, | |
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, | |
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 | |
], | |
[ | |
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, | |
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, | |
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, | |
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 | |
], | |
[ | |
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, | |
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, | |
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, | |
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 | |
] | |
] | |
proc toBin*[T](x: T): string = | |
toBin(x.BiggestInt, sizeof(T)*8) | |
type | |
bin64* = distinct uint64 | |
bin32* = distinct uint32 | |
type | |
Bit* = range[0..1] | |
BitArray* = seq[Bit] | |
converter toBin64*(x: bin32): bin64 = cast[uint64](x).bin64 | |
converter toBin64*(x: int64): bin64 = cast[uint64](x).bin64 | |
converter toBin32*(x: bin64): bin32 = cast[uint32](x).bin32 | |
func `shl`*(x: bin64, y: int): bin64 = (cast[uint64](x) shl y).bin64 | |
func `shr`*(x: bin64, y: int): bin64 = (cast[uint64](x) shr y).bin64 | |
func `and`*(x: bin64, y: bin64): bin64 = (cast[uint64](x) and cast[uint64](y)).bin64 | |
func `or`*(x: bin64, y: bin64): bin64 = (cast[uint64](x) or cast[uint64](y)).bin64 | |
func `xor`*(x: bin64, y: bin64): bin64 = (cast[uint64](x) xor cast[uint64](y)).bin64 | |
func getRightHalf*(x: bin64): bin32 = x.bin32 | |
func getLeftHalf*(x: bin64): bin32 = (x shr 32).bin32 | |
func `[]`*(x: bin64, pos: int): Bit = cast[Bit]((x shr pos) and cast[bin64](1)) | |
func `[]=`*(x: var bin64, pos: int, bit: Bit) = x = x or (cast[bin64](bit) shl pos) | |
func `[]=`*(x: var bin32, pos: int, bit: Bit) = x = x or (cast[bin32](bit) shl pos) | |
func `$`*(x: bin64): string = | |
for i in countdown(63,0): | |
result.add(cast[int](x[i])) | |
if i %% 4 == 0: | |
result.add(" ") | |
func `$`*(x: bin32): string = | |
for i in countdown(31,0): | |
result.add(cast[int](x[i])) | |
if i %% 4 == 0: | |
result.add(" ") | |
func toHex*(x: bin64): string = | |
"0x" & x.uint64.toHex() | |
func toString*(x: bin32): string = | |
for i in countdown(31,0): | |
result.add(cast[int](x[i])) | |
func getBitFromLeft*(x: bin64, pos: int): Bit = | |
cast[Bit]((x shr (63-pos)) and cast[bin64](1)) | |
# Deprecated | |
func getRightHalf*(x: uint64): uint32 = | |
x.uint32 | |
func getLeftHalf*(x: uint64): uint32 = | |
(x shr (64/2).int).uint32 | |
func getBitFromRight*(x: uint64, pos: int): uint64 = | |
(x shr pos) and 0x1 | |
func getBitFromLeft*(x: uint64, pos: int): uint64 = | |
(x shr (63 - pos)) and 0x1 | |
func setBit*(x: var uint64, pos: int, bit: uint64) = | |
x = x or (bit shl pos) | |
func `[]`*(x: uint64, pos: int): uint64 = | |
x.getBitFromLeft(pos) | |
func `[]=`*(x: var uint64, pos: int, bit: uint64) = | |
x = x or (bit shl (63 - pos)) | |
iterator getBitsFromRight*(x: uint64): uint64 = | |
for i in 0..64: | |
yield x.getBitFromRight(i) | |
iterator getBitsFromLeft*(x: uint64): uint64 = | |
for i in 0..64: | |
yield x.getBitFromLeft(i) | |
# var message: bin64 = 0b111000.bin64 | |
# echo message | |
# message[63] = 1 | |
# echo message | |
# echo message[3] | |
# echo message[4] | |
# BitArray | |
# From https://forum.nim-lang.org/t/354 | |
func newBitArray*(size: int): BitArray = | |
newSeq[Bit](size).BitArray | |
func `$`*(x: BitArray): string = | |
for i, item in x: | |
if i %% 4 == 0 and i > 0: | |
result.add(" ") | |
result.add(item) | |
func toBitArray*(x: bin64, size: int): BitArray = | |
result = newBitArray(size) | |
var resultI = 0 | |
for i in countdown(size-1,0): | |
result[resultI] = x[i] | |
inc(resultI) | |
converter toBitArray*(x: seq[int]): BitArray = | |
result = newBitArray(x.len) | |
for i,item in x: | |
result[i] = item | |
func toBin32*(b: BitArray): bin32 = | |
for i, item in b: | |
result[31-i] = item | |
func toUInt64*(b: BitArray): uint64 = | |
var resultIndex = 0 | |
for i in b: | |
result.setBit(63-resultIndex, i) | |
inc(resultIndex) | |
# func toBin64*(b: BitArray): bin64 = | |
# var resultI = 63 - b.len | |
# for i in b: | |
# result[resultI] = i | |
func U32toU64*(x: uint32):uint64 = | |
x.uint64 shl 32 | |
func getLeftHalf*(x: BitArray): BitArray = | |
result = newBitArray((x.len/2).int) | |
for i in 0 .. (x.high/2).int: | |
result[i] = x[i] | |
func getRightHalf*(x: BitArray): BitArray = | |
var length = (x.len/2).int | |
result = newBitArray(length) | |
for i in 0..<length: | |
result[i] = x[i+length] | |
func `shl`*(x: BitArray, y: int): BitArray = | |
result = newBitArray(x.len) | |
for i in 0..x.high: | |
# debugEcho x.high | |
result[i] = x[(i+y) mod x.len] | |
func `xor`*(x: BitArray, y: BitArray): BitArray = | |
result = newBitArray(x.len) | |
for i, item in x: | |
# debugEcho i | |
result[i] = item xor y[i] | |
# ## Array subtractor | |
# for i, it in IPminus1: | |
# var cols = 8 | |
# if it-1<10: | |
# stdout.write " " | |
# else: | |
# stdout.write " " | |
# stdout.write it-1, "," | |
# if i mod cols == cols-1: | |
# echo "" | |
# proc `[]`*(b: BitVector, i: Slice[int]): BitVector = | |
# if i.a < i.b: | |
# Base(b)[i] | |
# else: | |
# Base(b)[i.b .. i.a] | |
# proc `[]=`*(b: var BitVector; i: TSlice[int], value: BitVector) = ... | |
# proc `[]`*(b: BitArray, i: int): Bit = | |
# Base(b)[i div 32] shr (i mod 32) and 1 | |
# proc `[]=`*(b: var BitVector, i: int, value: Bit) = | |
# var w = addr Base(b)[i div 32] | |
# if value == 0: w[] = w[] and not (1'i32 shl (i mod 32)) | |
# else: w[] = w[] or (1'i32 shl (i mod 32)) | |
# proc bv*(s: string): BitVector = | |
# # idea: use bv"0010101" to construct bit vectors at compile time | |
# macro debug*(n: varargs[typed]): untyped = | |
# result = newNimNode(nnkStmtList, n) | |
# for i in 0..n.len-1: | |
# if n[i].kind == nnkStrLit: | |
# # pure string literals are written directly | |
# result.add(newCall("write", newIdentNode("stdout"), n[i])) | |
# else: | |
# # other expressions are written in <expression>: <value> syntax | |
# result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i]))) | |
# result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": "))) | |
# result.add(newCall("write", newIdentNode("stdout"), n[i])) | |
# if i != n.len-1: | |
# # separate by ", " | |
# result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(", "))) | |
# else: | |
# # add newline | |
# result.add(newCall("writeLine", newIdentNode("stdout"), newStrLitNode(""))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment