Skip to content

Instantly share code, notes, and snippets.

@konradmb
Created November 25, 2018 14:54
Show Gist options
  • Save konradmb/26342f35727730ca835144e4fae6ddbb to your computer and use it in GitHub Desktop.
Save konradmb/26342f35727730ca835144e4fae6ddbb to your computer and use it in GitHub Desktop.
Nim DES
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]
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