Skip to content

Instantly share code, notes, and snippets.

@jingoro
Created October 3, 2012 00:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jingoro/3824283 to your computer and use it in GitHub Desktop.
Save jingoro/3824283 to your computer and use it in GitHub Desktop.
FFX Radis Play
# /usr/bin/env ruby
#
# http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ffx/ffx-spec.pdf
# http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ffx/ffx-spec2.pdf
# http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ffx/ffx-ad-VAES3.pdf
require 'openssl'
def radix_block_prepend(radix, n, block)
if block.size < n
block = ('0' * (n - block.size)) + block
end
block
end
def radix_block_addition(radix, n, a, b)
sum = a.to_i(radix) + b.to_i(radix)
sum %= (radix ** n)
radix_block_prepend(radix, n, sum.to_s(radix))
end
def num_radix(radix, str, length)
# TODO: properly convert to radix
n = str.to_i(radix)
n_in_bits = n.to_s(2)
n_in_bits = ('0' * (length * 8)) + n_in_bits
n_in_bits = n_in_bits[-(length * 8)..-1]
[n_in_bits].pack('B*')
end
def str_xor(a, b)
aa = a.unpack("C*")
bb = b.unpack("C*")
raise "Strings must be the same length" unless aa.size == bb.size
aa.zip(bb).map{ |ca,cb| ca^cb }.pack("C*")
end
def aes(key, block)
aes = OpenSSL::Cipher::Cipher.new('aes-128-ecb')
aes.encrypt
aes.key = key
aes.update(block)
end
def cbc_mac(key, block)
raise "invalid block size" unless (block.size % 16 == 0)
y = "\0" * 16
i = 0
while i < block.size
x = block[i...(i+16)]
y = aes(key, str_xor(x, y))
i += 16
end
y
end
def byte_array_to_int(block)
result = 0
block.each_byte do |b|
result = (result << 8) + b
end
result
end
def f(radix, key, n, tweak, i, big_b)
method = 2
addition = 1
rnds = 10
vers = 1
t = tweak.size
beta = (n / 2.0).ceil
b = ((beta * Math.log(radix) / Math.log(2)).ceil / 8.0).ceil
d = 4 * (b/4.0).ceil
split_n = n / 2
if (i % 2) == 0
m = n / 2
else
m = (n / 2.0).ceil
end
#p [beta, b, d]
big_p = [vers, method, addition].pack('CCC') +
[radix].pack('N')[1..3] +
# the test suite doesn't seem to include this, but the spec does
[rnds].pack('C') +
[split_n].pack('C') +
[n].pack('N') +
[t].pack('N')
#p big_p.unpack('C*')
#p big_p.size
big_q = tweak +
"\0"*((-t-b-1)%16) +
[i].pack('C') +
num_radix(radix, big_b, b)
#p big_q.unpack('C*')
#p big_q.size
big_y = cbc_mac(key, big_p + big_q)
#p big_y.unpack('C*')
#p big_y.size
# TODO Y <- first d+4 bytes of ...
big_y = big_y[0...(d+4)]
y = byte_array_to_int(big_y)
z = y % (radix ** m)
result = radix_block_prepend(radix, m, z.to_s(radix))
#p result
result
end
def ffx_encrypt(radix, key, tweak, input)
n = input.size
l = n / 2
r = 10
big_a = input[0...l]
big_b = input[l...n]
0.upto(r - 1) do |i|
p big_b
f_out = f(radix, key, n, tweak, i, big_b)
p f_out
big_c = radix_block_addition(radix, big_a.size, big_a, f_out)
big_a = big_b
big_b = big_c
p [big_a, big_b]
end
big_a + big_b
end
key = ['2b7e151628aed2a6abf7158809cf4f3c'].pack('H*')
# p ffx_encrypt(10, key, "9876543210", "0123456789")
# p ffx_encrypt(10, key, "", "0123456789")
# p ffx_encrypt(10, key, "2718281828", "314159")
# p ffx_encrypt(10, key, "7777777", "999999999")
p ffx_encrypt(36, key, "TQF9J5QDAGSCSPB1", "C4XPWULBM3M863JH")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment