lib/crypt/idea.rb
# coding: ASCII
# IDEA (International Data Encryption Algorithm) by
# Xuejia Lai and James Massey (1992). Refer to license info at the end of this file.
require 'digest/md5'
require 'crypt/cbc'
module Crypt
class IDEA
include Crypt::CBC
ULONG = 0x100000000
USHORT = 0x10000
ENCRYPT = 0
DECRYPT = 1
def block_size
return(8)
end
def initialize(key128, mode)
# IDEA is subject to attack unless the key is sufficiently random, so we
# take an MD5 digest of a variable-length passphrase to ensure a solid key
if (key128.class == String)
digest = Digest::MD5.digest(key128)
key128 = digest.unpack('n'*8)
end
raise "Key must be 128 bits (8 words)" unless (key128.class == Array) && (key128.length == 8)
raise "Mode must be IDEA::ENCRYPT or IDEA::DECRYPT" unless ((mode == ENCRYPT) | (mode == DECRYPT))
if (mode == ENCRYPT)
@subkeys = generate_encryption_subkeys(key128)
else (mode == DECRYPT)
@subkeys = generate_decryption_subkeys(key128)
end
end
def mul(a, b)
modulus = 0x10001
return((1 - b) % USHORT) if (a == 0)
return((1 - a) % USHORT) if (b == 0)
return((a * b) % modulus)
end
def mul_inv(x)
modulus = 0x10001
x = x.to_i % USHORT
return(x) if (x <= 1)
t1 = USHORT / x
y = modulus % x
if (y == 1)
inv = (1 - t1) & 0xFFFF
return(inv)
end
t0 = 1
while (y != 1)
q = x / y
x = x % y
t0 = t0 + (q * t1)
return(t0) if (x == 1)
q = y / x
y = y % x
t1 = t1 + (q * t0)
end
inv = (1 - t1) & 0xFFFF
return(inv)
end
def generate_encryption_subkeys(key)
encrypt_keys = []
encrypt_keys[0..7] = key.dup
8.upto(51) { |i|
a = ((i + 1) % 8 > 0) ? (i-7) : (i-15)
b = ((i + 2) % 8 < 2) ? (i-14) : (i-6)
encrypt_keys[i] = ((encrypt_keys[a] << 9) | (encrypt_keys[b] >> 7)) % USHORT
}
return(encrypt_keys)
end
def generate_decryption_subkeys(key)
encrypt_keys = generate_encryption_subkeys(key)
decrypt_keys = []
decrypt_keys[48] = mul_inv(encrypt_keys.shift)
decrypt_keys[49] = (-encrypt_keys.shift) % USHORT
decrypt_keys[50] = (-encrypt_keys.shift) % USHORT
decrypt_keys[51] = mul_inv(encrypt_keys.shift)
42.step(0, -6) { |i|
decrypt_keys[i+4] = encrypt_keys.shift % USHORT
decrypt_keys[i+5] = encrypt_keys.shift % USHORT
decrypt_keys[i] = mul_inv(encrypt_keys.shift)
if (i ==0)
decrypt_keys[1] = (-encrypt_keys.shift) % USHORT
decrypt_keys[2] = (-encrypt_keys.shift) % USHORT
else
decrypt_keys[i+2] = (-encrypt_keys.shift) % USHORT
decrypt_keys[i+1] = (-encrypt_keys.shift) % USHORT
end
decrypt_keys[i+3] = mul_inv(encrypt_keys.shift)
}
return(decrypt_keys)
end
def crypt_pair(l, r)
word = [l, r].pack('NN').unpack('nnnn')
k = @subkeys[0..51]
8.downto(1) { |i|
word[0] = mul(word[0], k.shift)
word[1] = (word[1] + k.shift) % USHORT
word[2] = (word[2] + k.shift) % USHORT
word[3] = mul(word[3], k.shift)
t2 = word[0] ^ word[2]
t2 = mul(t2, k.shift)
t1 = (t2 + (word[1] ^ word[3])) % USHORT
t1 = mul(t1, k.shift)
t2 = (t1 + t2) % USHORT
word[0] ^= t1
word[3] ^= t2
t2 ^= word[1]
word[1] = word[2] ^ t1
word[2] = t2
}
result = []
result << mul(word[0], k.shift)
result << (word[2] + k.shift) % USHORT
result << (word[1] + k.shift) % USHORT
result << mul(word[3], k.shift)
two_longs = result.pack('nnnn').unpack('NN')
return(two_longs)
end
def encrypt_block(block)
xl, xr = block.unpack('NN')
xl, xr = crypt_pair(xl, xr)
encrypted = [xl, xr].pack('NN')
return(encrypted)
end
def decrypt_block(block)
xl, xr = block.unpack('NN')
xl, xr = crypt_pair(xl, xr)
decrypted = [xl, xr].pack('NN')
return(decrypted)
end
end
end
# IDEA LICENSE INFORMATION
#
# This software product contains the IDEA algorithm as described and claimed in
# US patent 5,214,703, EPO patent 0482154 (covering Austria, France, Germany,
# Italy, the Netherlands, Spain, Sweden, Switzerland, and the UK), and Japanese
# patent application 508119/1991, "Device for the conversion of a digital block
# and use of same" (hereinafter referred to as "the algorithm"). Any use of
# the algorithm for commercial purposes is thus subject to a license from Ascom
# Systec Ltd. of CH-5506 Maegenwil (Switzerland), being the patentee and sole
# owner of all rights, including the trademark IDEA.
#
# Commercial purposes shall mean any revenue generating purpose including but
# not limited to:
#
# i) Using the algorithm for company internal purposes (subject to a site
# license).
#
# ii) Incorporating the algorithm into any software and distributing such
# software and/or providing services relating thereto to others (subject to
# a product license).
#
# iii) Using a product containing the algorithm not covered by an IDEA license
# (subject to an end user license).
#
# All such end user license agreements are available exclusively from Ascom
# Systec Ltd and may be requested via the WWW at http://www.ascom.ch/systec or
# by email to idea@ascom.ch.
#
# Use other than for commercial purposes is strictly limited to non-revenue
# generating data transfer between private individuals. The use by government
# agencies, non-profit organizations, etc is considered as use for commercial
# purposes but may be subject to special conditions. Any misuse will be
# prosecuted.