class CryptoGost3411::Gost3411

Constants

Two512
Two64

Public Class Methods

new(digest_size=64) click to toggle source
# File lib/crypto_gost3411/gost3411.rb, line 4
def initialize(digest_size=64)
  if digest_size != 32 then         
    digest_size = 64
  end
  @digest_size = digest_size;
  # @resH - [8] uint64
  if @digest_size == 64 then
    @resH = [0,0,0,0,0,0,0,0]
  else
    e = uint8ToUint64("\x01" * 8)
    @resH = [e,e,e,e,e,e,e,e]
  end
  # [8] uint64
  @sigma = [0,0,0,0,0,0,0,0]
  # [8] uint64
  @nN = [0,0,0,0,0,0,0,0]
  # byte string
  @block = ''
  @block_len = 0      
end

Private Class Methods

add512(x, y) click to toggle source
# File lib/crypto_gost3411/gost3411.rb, line 124
def self.add512(x, y)
  x512 = x[7]
  (1...8).each do |i|
    x512 = x512*Two64 + x[7-i]
  end  
  y512 = y[7]
  (1...8).each do |i|
    y512 = y512*Two64 + y[7-i]
  end
  r512 = (x512 + y512)%Two512
  r = []
  (0...8).each do |i|
    r << r512%Two64
    r512 = (r512-r[-1])/Two64
  end
  r
end
printBytes(bytes, line_size = 16) click to toggle source
# File lib/crypto_gost3411/gost3411.rb, line 155
def self.printBytes(bytes, line_size = 16)
  bytes.unpack('H*')[0].scan(/.{1,#{line_size}}/).each{|s| puts(s)}
end

Public Instance Methods

digest(data) click to toggle source
# File lib/crypto_gost3411/gost3411.rb, line 72
def digest(data)
  update(data)
  dgst = final
end
final() click to toggle source
# File lib/crypto_gost3411/gost3411.rb, line 53
def final
  @block += 1.chr
  while @block.length < 64
    @block += 0.chr
  end
  # Don't increment @block_len for padding!
  transform(@block_len)
  zZ = [0,0,0,0,0,0,0,0]
  funcG(@resH, @nN, zZ)
  funcG(@resH, @sigma, zZ)
  dgst = ''
  @resH.each {|n| dgst += uint64ToUint8LE(n)}
  if @digest_size == 32
    dgst = dgst[32..-1]
  end  

  return dgst
end
update(data) click to toggle source
# File lib/crypto_gost3411/gost3411.rb, line 25
def update(data)
  bytes = data.dup.force_encoding('BINARY')
  bytes_len = bytes.length
  # Nothing to do for empty string
  if bytes_len > 0 then
    len = @block_len + bytes_len
    if len < 64 then
      @block += bytes
      @block_len = len
    else
      index = 0
      while len >= 64                       
        @block += bytes[index...(index + 64-@block_len)]
        transform(64)
        index += 64 - @block_len
        len -= 64
        @block = ''
        @block_len = 0
      end
      if len > 0 then
        @block = bytes[index...index + len]
        @block_len = len
      end
    end
  end
  return self
end

Private Instance Methods

funcG(h, m, n) click to toggle source

h, m, n - arrays of 64-bit numbers

# File lib/crypto_gost3411/gost3411.rb, line 108
def funcG(h, m, n)
  kk = [0,0,0,0,0,0,0,0]
  tt = [0,0,0,0,0,0,0,0]
  funcLPSX(kk, h, n)
  funcLPSX(tt, kk, m)
  funcLPSX(kk, kk, C16[0])
  (1...12).each do |i|
    funcLPSX(tt, kk, tt)
    funcLPSX(kk, kk, C16[i])
  end
  
  (0...8).each do |i|
    h[i] ^= tt[i] ^ kk[i] ^ m[i]
  end
end
funcLPSX(out, a, b) click to toggle source

out, a, b, temp - arrays

# File lib/crypto_gost3411/gost3411.rb, line 101
def funcLPSX(out, a, b)
  temp = [0,0,0,0,0,0,0,0]
  (0...a.length).each{|i| temp[i] = a[i] ^ b[i]}
  (0...temp.length).each{|i| strido(out, temp, i)}
end
printCtx() click to toggle source
# File lib/crypto_gost3411/gost3411.rb, line 159
def printCtx
  puts '='*16 + ' Digest context ' + '='*16
  puts "digest_size = #{@digest_size}"
  puts "block_len = #{@block_len}"
  puts 'block:'
  self.class.printBytes(@block)
  puts 'resH:'
  (0...8).each do |i|
    printf("0x%X\n", @resH[i])
  end
  puts 'nN:'
  (0...8).each do |i|
    printf("0x%X\n", @nN[i])
  end
  puts 'sigma:'
  (0...8).each do |i|
    printf("0x%X\n", @sigma[i])
  end
  puts "="*40
end
strido(out, temp, i) click to toggle source

out, temp - arrays

# File lib/crypto_gost3411/gost3411.rb, line 94
def strido(out, temp, i)   
  t  = Gost3411Table[0][(temp[0] >> (i * 8)) & 0xff]
  (1...8).each{|j| t ^= Gost3411Table[j][(temp[j] >> (i * 8)) & 0xff]}    
  out[i] = t 
end
transform(nbytes) click to toggle source
# File lib/crypto_gost3411/gost3411.rb, line 142
def transform(nbytes)
  count512 = [nbytes*8,0,0,0,0,0,0,0]
  mM = []
  (0...8).each do |i|
    mM << uint8ToUint64(@block[(i * 8)...(i * 8 + 8)])
  end  

  funcG(@resH, mM, @nN)
  
  @nN = self.class.add512(@nN, count512)
  @sigma = self.class.add512(@sigma, mM)
end
uint64ToUint8LE(n) click to toggle source

Unload 64-bit number to 8-byte string (little-endian, adding leading zeroes)

# File lib/crypto_gost3411/gost3411.rb, line 84
def uint64ToUint8LE(n)
  [n % 0x100000000].pack("V") + [n / 0x100000000].pack("V")
end
uint8ToUint64(bytes) click to toggle source

Unpack 8-byte (little-endian) string to 64-bit number (native-endian)

# File lib/crypto_gost3411/gost3411.rb, line 89
def uint8ToUint64(bytes)
  bytes.unpack('Q*')[0]
end