class GostKuznyechik::Kuznyechik
Base abstract class
Constants
- BigEndian
's' stands for native-endian byte order but 'n' stands for network (big-endian) byte order
- BlockLengthInBytes
class constants
- KeyLengthInBytes
- MaxIvLength
- NumberOfRounds
- NumberOfRoundsInKeySchedule
Protected Class Methods
decryptBlock(block, keys)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 173 def self.decryptBlock(block, keys) pair = block.scan(/.{8}/m) data = [] # Format 'Q*' unpacks byte string using native byte order data << pair[0].unpack('Q*')[0] data << pair[1].unpack('Q*')[0] round = NumberOfRounds - 1 # round == 9 data[0] ^= keys[2 * round] data[1] ^= keys[2 * round + 1] round -= 1 # round == 8 data[0] = funcS(data[0]) data[1] = funcS(data[1]) cache = funcInvLS(data) data = funcInvLS(cache) cache[0] = data[0] ^ keys[2 * round] cache[1] = data[1] ^ keys[2 * round + 1] round -= 1 # round = 7 (NumberOfRounds - 3).downto(1) do |i| data = funcInvLS(cache) cache[0] = data[0] ^ keys[2 * round] cache[1] = data[1] ^ keys[2 * round + 1] round -= 1 end # round == 0 cache[0] = funcInvS(cache[0]) cache[1] = funcInvS(cache[1]) data[0] = cache[0] ^ keys[2 * round] data[1] = cache[1] ^ keys[2 * round + 1] output = uint64ToUint8(data[0]) + uint64ToUint8(data[1]) output end
encryptBlock(block, keys)
click to toggle source
block - 16-byte String
# File lib/gost_kuznyechik/kuznyechik.rb, line 152 def self.encryptBlock(block, keys) pair = block.scan(/.{8}/m) data = [] # Format 'Q*' unpacks byte string using native byte order data << pair[0].unpack('Q*')[0] data << pair[1].unpack('Q*')[0] cache = [0, 0] (0...(NumberOfRounds - 1)).each do |round| cache[0] = data[0] ^ keys[2 * round] cache[1] = data[1] ^ keys[2 * round + 1] data = funcLS(cache) end data[0] ^= keys[2 * (NumberOfRounds - 1)] data[1] ^= keys[2 * (NumberOfRounds - 1) + 1]; output = uint64ToUint8(data[0]) + uint64ToUint8(data[1]) output end
expandDecryptKeys(inkey)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 54 def self.expandDecryptKeys(inkey) roundKeys = expandEncryptKeys(inkey) cache = [0, 0] (1..8).each do |i| cache[0] = roundKeys[2 * i] cache[1] = roundKeys[2 * i + 1] cache[0] = funcS(cache[0]) cache[1] = funcS(cache[1]) pair = funcInvLS(cache) roundKeys[2 * i] = pair[0] roundKeys[2 * i + 1] = pair[1] end roundKeys end
expandEncryptKeys(inkey)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 41 def self.expandEncryptKeys(inkey) roundKeys = inkey.dup constantIndex = 0 (2...NumberOfRounds).step(2) do |iNextKey| roundKeys += roundKeys[-4..-1] (0...NumberOfRoundsInKeySchedule).each do |iFeistel| funcF(constantIndex, roundKeys, iNextKey * 2) constantIndex += 1 end end roundKeys end
funcF(constantIndex, roundKeys, index)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 69 def self.funcF(constantIndex, roundKeys, index) temp1 = [] temp1 << (roundKeys[index] ^ RoundConstLeft[constantIndex]); temp1 << (roundKeys[index+1] ^ RoundConstRight[constantIndex]); temp2 = funcLS(temp1) roundKeys[index+2] ^= temp2[0]; roundKeys[index+3] ^= temp2[1]; swapBlocks(roundKeys, index); end
funcInvLS(input)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 95 def self.funcInvLS(input) # To little-endian na = [] ns = uint64ToUint8BE(input[0]).reverse na += ns.unpack('C*') ns = uint64ToUint8BE(input[1]).reverse na += ns.unpack('C*') left = 0 right = 0 na.each_with_index do |v, i| left ^= PrecInvLSTableLeft[i][v] right ^= PrecInvLSTableRight[i][v] end [left, right] end
funcInvS(n)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 33 def self.funcInvS(n) uint64ToUint8(n).unpack('C*').map{|b| InvPiTable[b]}.pack('C*').unpack('Q*')[0] end
funcLS(input)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 79 def self.funcLS(input) # To little-endian na = [] ns = uint64ToUint8BE(input[0]).reverse na += ns.unpack('C*') ns = uint64ToUint8BE(input[1]).reverse na += ns.unpack('C*') left = 0 right = 0 na.each_with_index do |v, i| left ^= PrecLSTableLeft[i][v] right ^= PrecLSTableRight[i][v] end [left, right] end
funcS(n)
click to toggle source
n - 64-bit number
# File lib/gost_kuznyechik/kuznyechik.rb, line 29 def self.funcS(n) uint64ToUint8(n).unpack('C*').map{|b| PiTable[b]}.pack('C*').unpack('Q*')[0] end
incrementModulo(counter, size)
click to toggle source
Increment CTR counter
# File lib/gost_kuznyechik/kuznyechik.rb, line 210 def self.incrementModulo(counter, size) lastIndex = size - 1 (0...size).each do |i| if counter[lastIndex - i].ord > 0xfe then counter[lastIndex - i] = (counter[lastIndex - i].ord - 0xff).chr else counter[lastIndex - i] = (counter[lastIndex - i].ord + 1).chr break end end counter end
keyToNumbers(key)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 37 def self.keyToNumbers(key) inkey = key.scan(/.{8}/m).map{|k| k.unpack('Q*')[0]} end
padd(incomplete_block)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 237 def self.padd(incomplete_block) padding_len = BlockLengthInBytes - (incomplete_block.length % BlockLengthInBytes) padded_block = incomplete_block.dup padded_block += 0x80.chr padding_len -= 1 if padding_len > 0 then padded_block += 0.chr * padding_len end padded_block end
printBytes(bytes, line_size = 16)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 16 def self.printBytes(bytes, line_size = 16) bytes.unpack('H*')[0].scan(/.{1,#{line_size}}/).each{|s| puts(s)} end
shiftLeftOne(block)
click to toggle source
block - byte string
# File lib/gost_kuznyechik/kuznyechik.rb, line 224 def self.shiftLeftOne(block) (0...(BlockLengthInBytes-1)).each do |i| ri1 = block[i+1].ord ri = block[i].ord << 1 ri &= 0xfe ri |= (ri1 >> 7) & 0x1 block[i] = ri.chr end ri = block[BlockLengthInBytes-1].ord << 1 block[BlockLengthInBytes-1] = (ri & 0xfe).chr block end
swapBlocks(roundKeys, index)
click to toggle source
roundKeys - array of 64-bit numbers index - points to left number index+2 - points to right number swaps left block with right block
# File lib/gost_kuznyechik/kuznyechik.rb, line 115 def self.swapBlocks(roundKeys, index) roundKeys[index] ^= roundKeys[index+2] roundKeys[index+1] ^= roundKeys[index+3] roundKeys[index+2] ^= roundKeys[index] roundKeys[index+3] ^= roundKeys[index+1] roundKeys[index] ^= roundKeys[index+2] roundKeys[index+1] ^= roundKeys[index+3] end
uint64ToUint8(n)
click to toggle source
Unload 64-bit number to 8-byte string (native-endian, adding leading zeroes)
# File lib/gost_kuznyechik/kuznyechik.rb, line 139 def self.uint64ToUint8(n) bytes = uint64ToUint8BE(n) bytes.reverse! unless BigEndian bytes end
uint64ToUint8BE(n)
click to toggle source
Unload 64-bit number to 8-byte string (big-endian, adding leading zeroes)
# File lib/gost_kuznyechik/kuznyechik.rb, line 128 def self.uint64ToUint8BE(n) str = n.to_s(16) # big-endian len = str.length # add leading zeroes str.insert(0, '0'*(16 - len)) if len < 16 # To byte string bytes = [str].pack('H*') end
uint8ToUint64(bytes)
click to toggle source
Unpacks 8-byte string to 64-bit number (native-endian)
# File lib/gost_kuznyechik/kuznyechik.rb, line 147 def self.uint8ToUint64(bytes) bytes.unpack('Q*')[0] end
zeroBlock()
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 24 def self.zeroBlock ("\x00"*BlockLengthInBytes).force_encoding('BINARY') end
zeroBytes(n)
click to toggle source
# File lib/gost_kuznyechik/kuznyechik.rb, line 20 def self.zeroBytes(n) ("\x00"*n).force_encoding('BINARY') end