lib/crypt/gost.rb
# coding: ASCII
# adapted from C++ code written by Wei Dai
# of the Crypto++ project http://www.eskimo.com/~weidai/cryptlib.html
require 'crypt/cbc'
require 'crypt/block_methods'
module Crypt
class Gost
include CBC
include BlockMethods
ULONG = 0x100000000
def block_size
return(8)
end
def initialize(user_key)
# These are the S-boxes given in Applied Cryptography 2nd Ed., p. 333
@sBox = [
[4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3],
[14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9],
[5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11],
[7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3],
[6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2],
[4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14],
[13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12],
[1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12]
]
# These are the S-boxes given in the GOST source code listing in Applied
# Cryptography 2nd Ed., p. 644. They appear to be from the DES S-boxes
# [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 ],
# [ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 ],
# [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 ],
# [ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 ],
# [ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 ],
# [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 ],
# [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 ],
# [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 ]
# precalculate the S table
@s_table = precalculate_s_table()
# derive the 32-byte key from the user-supplied key
user_key_length = user_key.length
@key = user_key[0..31].unpack('C'*32)
if (user_key_length < 32)
user_key_length.upto(31) { @key << 0 }
end
end
def precalculate_s_table()
s_table = [[], [], [], []]
0.upto(3) { |i|
0.upto(255) { |j|
t = @sBox[2*i][j % 16] | (@sBox[2*i+1][j/16] << 4)
u = (8*i + 11) % 32
v = (t << u) | (t >> (32-u))
s_table[i][j] = (v % ULONG)
}
}
return(s_table)
end
def f(long_word)
long_word = long_word % ULONG
a, b, c, d = [long_word].pack('L').unpack('CCCC')
return(@s_table[3][d] ^ @s_table[2][c] ^ @s_table[1][b] ^ @s_table[0][a])
end
def encrypt_pair(xl, xr)
3.times {
xr ^= f(xl+@key[0])
xl ^= f(xr+@key[1])
xr ^= f(xl+@key[2])
xl ^= f(xr+@key[3])
xr ^= f(xl+@key[4])
xl ^= f(xr+@key[5])
xr ^= f(xl+@key[6])
xl ^= f(xr+@key[7])
}
xr ^= f(xl+@key[7])
xl ^= f(xr+@key[6])
xr ^= f(xl+@key[5])
xl ^= f(xr+@key[4])
xr ^= f(xl+@key[3])
xl ^= f(xr+@key[2])
xr ^= f(xl+@key[1])
xl ^= f(xr+@key[0])
return([xr, xl])
end
def decrypt_pair(xl, xr)
xr ^= f(xl+@key[0])
xl ^= f(xr+@key[1])
xr ^= f(xl+@key[2])
xl ^= f(xr+@key[3])
xr ^= f(xl+@key[4])
xl ^= f(xr+@key[5])
xr ^= f(xl+@key[6])
xl ^= f(xr+@key[7])
3.times {
xr ^= f(xl+@key[7])
xl ^= f(xr+@key[6])
xr ^= f(xl+@key[5])
xl ^= f(xr+@key[4])
xr ^= f(xl+@key[3])
xl ^= f(xr+@key[2])
xr ^= f(xl+@key[1])
xl ^= f(xr+@key[0])
}
return([xr, xl])
end
end
end