#! /usr/bin/env ruby
module Raptcha
#--{{{
VERSION = '0.0.1' unless defined? Raptcha::VERSION
def self.version() VERSION end
require 'base64'
require 'socket'
begin
require 'rubygems'
rescue LoadError
nil
end
begin
require 'RMagick'
rescue LoadError
begin
require 'Rmagick'
rescue LoadError
require 'rmagick'
end
end
=begin
#--{{{
# all of this in inlined in the BEGIN block below...
libdir = __FILE__.gsub %r'\.rb$', '/'
begin
$:.unshift libdir
require 'pervasives'
require 'attributes'
require 'crypt/blowfish'
ensure
$:.shift
end
#--}}}
=end
module Image
#--{{{
singleton_class =
class << self
self
end
singleton_class.module_eval do
attribute('key'){ "--img--#{ Raptcha.mac_address }--#{ Raptcha.hostname }--"[0,56] }
attribute('distort'){ Hash[
:low => [0, 100],
:medium => [3, 50],
:high => [5, 30],
] }
attribute('default'){ Hash[
:width => 142,
:height => 30,
:distort => :medium,
#:background => 'black',
#:foreground => 'springgreen',
:background => 'white',
:foreground => 'springgreen3',
:format => 'png',
:font_family => 'monoco',
:pointsize => 22,
:implode => 0.2,
] }
def create kw = {}
kw = default.update kw.to_options
word = kw[:word]
encrypted = kw[:encrypted] || kw[:e]
word ||= Raptcha.decrypt(encrypted, :key => key) if encrypted
word ||= Raptcha.word
word = word.split(%r"").join(" ")
kw[:width] = kw[:width].to_i
kw[:height] = kw[:height].to_i
kw[:implode] = kw[:implode].to_f
img = Magick::Image.new(kw[:width], kw[:height]) do |i|
i.background_color = kw[:background]
i.format = kw[:format]
end
draw = Magick::Draw.new
# text
draw.stroke = kw[:foreground]
draw.stroke_width = 0
draw.font_family = kw[:font_family]
draw.pointsize = kw[:pointsize]
#draw.pointsize = kw[:height] * 0.75
draw.fill = kw[:foreground]
draw.gravity = Magick::NorthGravity
draw.annotate img, 0, 0, 5, 5, word
# line
draw.stroke = kw[:foreground]
draw.stroke_width = 1
#draw.line 5, kw[:height]*0.33, kw[:width]-5, kw[:height]*0.33
#draw.line 5, kw[:height]*0.66, kw[:width]-5, kw[:height]*0.66
draw.line 5, kw[:height]*0.65, kw[:width]-5, kw[:height]*0.65
draw.draw img
img = img.wave *distort[kw[:distort]]
img = img.implode kw[:implode]
img.to_blob
end
def inline kw ={}
Base64.encode64(create(kw))
end
end
#--}}}
end
class Error < ::StandardError; end
class NoInput < Error; end
class BadInput < Error; end
class Expired < Error; end
singleton_class =
class << self
self
end
singleton_class.module_eval do
attribute('key'){ "--key--#{ mac_address }--#{ hostname }--"[0,56] }
attribute('src'){ '/raptcha' }
attribute('gravity'){ 'west' }
attribute('hostname'){ Socket.gethostname }
attribute('user'){ ENV['USER'] || ENV['LOGNAME'] || 'raptcha' }
attribute('alphabet'){ ('A' .. 'Z').to_a }
attribute('ttl'){ 30 * 60 }
attribute('close_enough'){ Hash[
'0OoQ' => '0',
'1l' => '1',
'2zZ' => '2',
'5sS' => '5',
'kKxX' => 'x',
] }
def valid? params
#--{{{
begin
validate! params
rescue NoInput
nil
rescue BadInput
false
rescue Expired
false
end
#--}}}
end
def validate! params
#--{{{
if params.has_key? 'raptcha'
raptcha = params['raptcha']
textarea = raptcha['t']
word = raptcha['w']
timebomb = raptcha['b']
raise NoInput unless textarea and word and timebomb
word = decrypt word
timebomb = decrypt timebomb
begin
timebomb = Integer timebomb
timebomb = Time.at(timebomb).utc
now = Time.now.utc
raise Expired unless now < timebomb
rescue
raise Expired
end
raise BadInput unless fuzzy(word) == fuzzy(textarea)
textarea
else
validate! 'raptcha' => params
end
#--}}}
end
def fuzzy word
#--{{{
result = word.to_s.downcase
close_enough.each do |charset, replace|
result.gsub! %r"[#{ charset }]", replace
end
result
#--}}}
end
attribute 'input_north'
attribute 'input_south'
attribute 'input_east'
attribute 'input_west'
def input kw = {}
#--{{{
kw.to_options!
kw[:src] ||= Raptcha.src
kw[:word] ||= Raptcha.word
kw[:timebomb] ||= Raptcha.timebomb
kw[:gravity] ||= Raptcha.gravity
encrypted_word = encrypt kw[:word], :key => Raptcha.key
encrypted_timebomb = encrypt kw[:timebomb], :key => Raptcha.key
west = north = east = south = nil
case gravity.to_s
when /w(est)?/
west = Raptcha.img(kw)
when /n(orth)?/
north = Raptcha.img(kw) + '
'
when /e(ast)?/
east = Raptcha.img(kw)
when /s(outh)?/
south = '
' + Raptcha.img(kw)
end
<<-html
#{ input_north }#{ input_west }
#{ north } #{ west }
#{ east } #{ south }
#{ input_east } #{ input_south }
html
#--}}}
end
alias_method "tag", "input"
def img kw = {}
#--{{{
kw.to_options!
return(inline(kw)) if kw[:inline]
src = kw[:src] || Raptcha.src
word = kw[:word] || Raptcha.word
encrypted_word = encrypt word, :key => Image.key
<<-html
html
#--}}}
end
def inline kw = {}
#--{{{
<<-html
html
#--}}}
end
def timebomb
#--{{{
Time.now.utc.to_i + Raptcha.ttl
#--}}}
end
def word size = 6
#--{{{
w = '' and size.times{ w << alphabet[rand(alphabet.size - 1)]} and w
#--}}}
end
def image *a, &b
#--{{{
Raptcha::Image.create *a, &b
#--}}}
end
def mac_address
#--{{{
return @mac_address if defined? @mac_address
re = %r/[^:\-](?:[0-9A-F][0-9A-F][:\-]){5}[0-9A-F][0-9A-F][^:\-]/io
cmds = '/sbin/ifconfig', '/bin/ifconfig', 'ifconfig', 'ipconfig /all'
null = test(?e, '/dev/null') ? '/dev/null' : 'NUL'
lines = nil
cmds.each do |cmd|
stdout = IO.popen("#{ cmd } 2> #{ null }"){|fd| fd.readlines} rescue next
next unless stdout and stdout.size > 0
lines = stdout and break
end
raise "all of #{ cmds.join ' ' } failed" unless lines
candidates = lines.select{|line| line =~ re}
raise 'no mac address candidates' unless candidates.first
candidates.map!{|c| c[re]}
maddr = candidates.first
raise 'no mac address found' unless maddr
maddr.strip!
maddr.instance_eval{ @list = candidates; def list() @list end }
@mac_address = maddr
#--}}}
end
def blowfish
#--{{{
@blowfish ||= Hash.new{|h,k| h[k] = Crypt::Blowfish.new(k)}
#--}}}
end
def encrypt string, kw = {}
#--{{{
kw.to_options!
k = kw[:key] || key
Base64.encode64(blowfish[k].encrypt_string(string.to_s)).chop # kill "\n"
#--}}}
end
def decrypt string, kw = {}
#--{{{
kw.to_options!
k = kw[:key] || key
blowfish[k].decrypt_string(Base64.decode64("#{ string }\n")).strip
#--}}}
end
def render controller, params
#--{{{
controller.instance_eval do
send_data Raptcha.image(params), :type => 'image/png', :disposition => 'inline', :filename => 'raptcha.png'
end
#--}}}
end
end
#--}}}
end
if $0 == __FILE__
#--{{{
(( Main = Object.new )).instance_eval do
def run
@argv = ARGV.dup
mode = @argv.detect{|arg| arg !~ %r"[=:]"} || 'raptcha'
@argv.delete mode
send mode
end
def raptcha
kw = {}
@argv.each{|kv| k, v = kv.split(%r"[=:]").map{|x| x.strip}; kw.update k => v}
STDOUT.write Raptcha.image(kw)
end
def generate
what = @argv.shift
send "generate_#{ what }"
end
def generate_controller
src = DATA.read
if test ?d, 'app'
path = File.join 'app', 'controllers', 'raptcha_controller.rb'
if test ?e, path
puts "exists #{ path }"
exit 1
end
open path, 'w' do |fd|
fd.puts src
end
puts "#{ path }"
else
puts "generated #{ src }"
end
end
def generate_lib
src = IO.read(__FILE__)
if test ?d, 'app'
path = File.join 'lib', 'raptcha.rb'
if test ?e, path
puts "exists #{ path }"
exit 1
end
open path, 'w' do |fd|
fd.puts src
end
puts "#{ path }"
else
puts "generated #{ src }"
end
end
end
Main.run
#--}}}
end
BEGIN {
#--{{{
unless Hash.new.respond_to? 'to_options' #--{{{
def to_options
inject(Hash.new){|h, kv| h.update kv.first.to_s.to_sym => kv.last}
end
def to_options!
h = to_options
clear
update h
end
end #--}}}
module Pervasives #--{{{
VERSION = "1.0.0" unless defined? Pervasives::VERSION
def self.version() VERSION end
class ::Class
def __pervasive__ m, *a, &b
(( Class.instance_method(m) rescue Module.instance_method(m) rescue Object.instance_method(m) )).bind(self).call(*a, &b)
end
end
class ::Module
def __pervasive__ m, *a, &b
(( Module.instance_method(m) rescue Object.instance_method(m) )).bind(self).call(*a, &b)
end
end
class ::Object
def __pervasive__ m, *a, &b
(( Object.instance_method(m) )).bind(self).call(*a, &b)
end
end
class Proxy
instance_methods.each{|m| undef_method m unless m[%r/__/]}
def initialize obj
@obj = obj
end
def method_missing m, *a, &b
@obj.__pervasive__ m, *a, &b
end
def __obj__
@obj
end
end
end #--}}}
module Attributes #--{{{
VERSION = '3.5.0'
def self.version() VERSION end
def attributes *a, &b
unless a.empty?
hashes, names = a.partition{|x| Hash === x}
names_and_defaults = {}
hashes.each{|h| names_and_defaults.update h}
names.flatten.compact.each{|name| names_and_defaults.update name => nil}
names_and_defaults.each do |name, default|
init = b || lambda { default }
ivar, getter, setter, query, banger =
"@#{ name }", "#{ name }", "#{ name }=", "#{ name }?", "#{ name }!"
define_method(setter) do |value|
__pervasive__('instance_variable_set', ivar, value)
end
define_method(getter) do |*value|
unless value.empty?
__pervasive__('send', setter, value.shift)
else
defined = __pervasive__('instance_eval', "defined? #{ ivar }")
__pervasive__('send', setter, __pervasive__('instance_eval', &init)) unless defined
__pervasive__('instance_variable_get', ivar)
end
end
define_method(banger) do
__pervasive__('send', setter, __pervasive__('instance_eval', &init))
__pervasive__('instance_variable_get', ivar)
end
alias_method query, getter
(attributes << name.to_s).uniq!
attributes
end
else
begin
__attribute_list__
rescue NameError
singleton_class =
class << self
self
end
klass = self
singleton_class.module_eval do
attribute_list = []
define_method('attribute_list'){ klass == self ? attribute_list : raise(NameError) }
alias_method '__attribute_list__', 'attribute_list'
end
__attribute_list__
end
end
end
%w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
end
class Object
def attributes *a, &b
sc =
class << self
self
end
sc.attributes *a, &b
end
%w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
end
class Module
include Attributes
end #--}}}
# cbc.rb Richard Kernahan
module Crypt #--{{{
module CBC
require 'stringio'
#require 'crypt/stringxor'
ULONG = 0x100000000
# When this module is mixed in with an encryption class, the class
# must provide three methods: encrypt_block(block) and decrypt_block(block)
# and block_size()
def generate_initialization_vector(words)
srand(Time.now.to_i)
vector = ""
words.times {
vector << [rand(ULONG)].pack('N')
}
return(vector)
end
def encrypt_stream(plainStream, cryptStream)
# Cypher-block-chain mode
initVector = generate_initialization_vector(block_size() / 4)
chain = encrypt_block(initVector)
cryptStream.write(chain)
while ((block = plainStream.read(block_size())) && (block.length == block_size()))
block = block ^ chain
encrypted = encrypt_block(block)
cryptStream.write(encrypted)
chain = encrypted
end
# write the final block
# At most block_size()-1 bytes can be part of the message.
# That means the final byte can be used to store the number of meaningful
# bytes in the final block
block = '' if block.nil?
buffer = block.split('')
remainingMessageBytes = buffer.length
# we use 7-bit characters to avoid possible strange behavior on the Mac
remainingMessageBytes.upto(block_size()-2) { buffer << rand(128).chr }
buffer << remainingMessageBytes.chr
block = buffer.join('')
block = block ^ chain
encrypted = encrypt_block(block)
cryptStream.write(encrypted)
end
def decrypt_stream(cryptStream, plainStream)
# Cypher-block-chain mode
chain = cryptStream.read(block_size())
while (block = cryptStream.read(block_size()))
decrypted = decrypt_block(block)
plainText = decrypted ^ chain
plainStream.write(plainText) unless cryptStream.eof?
chain = block
end
# write the final block, omitting the padding
buffer = plainText.split('')
remainingMessageBytes = buffer.last.unpack('C').first
remainingMessageBytes.times { plainStream.write(buffer.shift) }
end
def carefully_open_file(filename, mode)
begin
aFile = File.new(filename, mode)
rescue
puts "Sorry. There was a problem opening the file <#{filename}>."
aFile.close() unless aFile.nil?
raise
end
return(aFile)
end
def encrypt_file(plainFilename, cryptFilename)
plainFile = carefully_open_file(plainFilename, 'rb')
cryptFile = carefully_open_file(cryptFilename, 'wb+')
encrypt_stream(plainFile, cryptFile)
plainFile.close unless plainFile.closed?
cryptFile.close unless cryptFile.closed?
end
def decrypt_file(cryptFilename, plainFilename)
cryptFile = carefully_open_file(cryptFilename, 'rb')
plainFile = carefully_open_file(plainFilename, 'wb+')
decrypt_stream(cryptFile, plainFile)
cryptFile.close unless cryptFile.closed?
plainFile.close unless plainFile.closed?
end
def encrypt_string(plainText)
plainStream = StringIO.new(plainText)
cryptStream = StringIO.new('')
encrypt_stream(plainStream, cryptStream)
cryptText = cryptStream.string
return(cryptText)
end
def decrypt_string(cryptText)
cryptStream = StringIO.new(cryptText)
plainStream = StringIO.new('')
decrypt_stream(cryptStream, plainStream)
plainText = plainStream.string
return(plainText)
end
end
end #--}}}
# blowfish-tables.rb Richard Kernahan
module Crypt #--{{{
module BlowfishTables
INITIALPARRAY = [
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
]
INITIALSBOXES = [[
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a], [
0x4b7a70e9, 0xb5b32944,
0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29,
0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26,
0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c,
0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6,
0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f,
0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810,
0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa,
0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55,
0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1,
0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78,
0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883,
0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170,
0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7,
0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099,
0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263,
0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3,
0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7,
0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d,
0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460,
0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484,
0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a,
0xe6e39f2b, 0xdb83adf7], [
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a,
0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785,
0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900,
0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9,
0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397,
0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9,
0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f,
0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e,
0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd,
0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8,
0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c,
0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b,
0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386,
0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0,
0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2,
0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770,
0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c,
0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa,
0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63,
0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9,
0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4,
0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0], [
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6]
]
end
end #--}}}
# blowfish.rb Richard Kernahan
#
# Blowfish algorithm by Bruce Schneider
# Ported by Richard Kernahan from the reference C code
module Crypt #--{{{
class Blowfish
#require 'crypt/cbc'
include Crypt::CBC
#require 'crypt/blowfish-tables'
include Crypt::BlowfishTables
ULONG = 0x100000000
def block_size
return(8)
end
def initialize(key)
@key = key
raise "Bad key length: the key must be 1-56 bytes." unless (key.length.between?(1,56))
@pArray = []
@sBoxes = []
setup_blowfish()
end
def f(x)
a, b, c, d = [x].pack('N').unpack('CCCC')
y = (@sBoxes[0][a] + @sBoxes[1][b]) % ULONG
y = (y ^ @sBoxes[2][c]) % ULONG
y = (y + @sBoxes[3][d]) % ULONG
return(y)
end
def setup_blowfish()
@sBoxes = Array.new(4) { |i| INITIALSBOXES[i].clone }
@pArray = INITIALPARRAY.clone
keypos = 0
0.upto(17) { |i|
data = 0
4.times {
data = ((data << 8) | @key[keypos]) % ULONG
keypos = (keypos.next) % @key.length
}
@pArray[i] = (@pArray[i] ^ data) % ULONG
}
l = 0
r = 0
0.step(17, 2) { |i|
l, r = encrypt_pair(l, r)
@pArray[i] = l
@pArray[i+1] = r
}
0.upto(3) { |i|
0.step(255, 2) { |j|
l, r = encrypt_pair(l, r)
@sBoxes[i][j] = l
@sBoxes[i][j+1] = r
}
}
end
def encrypt_pair(xl, xr)
0.upto(15) { |i|
xl = (xl ^ @pArray[i]) % ULONG
xr = (xr ^ f(xl)) % ULONG
xl, xr = [xl, xr].reverse
}
xl, xr = [xl, xr].reverse
xr = (xr ^ @pArray[16]) % ULONG
xl = (xl ^ @pArray[17]) % ULONG
return([xl, xr])
end
def decrypt_pair(xl, xr)
17.downto(2) { |i|
xl = (xl ^ @pArray[i]) % ULONG
xr = (xr ^ f(xl)) % ULONG
xl, xr = [xl, xr].reverse
}
xl, xr = [xl, xr].reverse
xr = (xr ^ @pArray[1]) % ULONG
xl = (xl ^ @pArray[0]) % ULONG
return([xl, xr])
end
def encrypt_block(block)
xl, xr = block.unpack('NN')
xl, xr = encrypt_pair(xl, xr)
encrypted = [xl, xr].pack('NN')
return(encrypted)
end
def decrypt_block(block)
xl, xr = block.unpack('NN')
xl, xr = decrypt_pair(xl, xr)
decrypted = [xl, xr].pack('NN')
return(decrypted)
end
end
end #--}}}
# gost.rb
# Adapted by Richard Kernahan
# from C++ code written by Wei Dai
# of the Crypto++ project http://www.eskimo.com/~weidai/cryptlib.html
module Crypt #--{{{
class Gost
#require 'crypt/cbc'
include CBC
ULONG = 0x100000000
def block_size
return(8)
end
def initialize(userKey)
# 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
@sTable = precalculate_S_table()
# derive the 32-byte key from the user-supplied key
userKeyLength = userKey.length
@key = userKey[0..31].unpack('C'*32)
if (userKeyLength < 32)
userKeyLength.upto(31) { @key << 0 }
end
end
def precalculate_S_table()
sTable = [[], [], [], []]
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))
sTable[i][j] = (v % ULONG)
}
}
return(sTable)
end
def f(longWord)
longWord = longWord % ULONG
a, b, c, d = [longWord].pack('L').unpack('CCCC')
return(@sTable[3][d] ^ @sTable[2][c] ^ @sTable[1][b] ^ @sTable[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
def encrypt_block(block)
xl, xr = block.unpack('NN')
xl, xr = encrypt_pair(xl, xr)
encrypted = [xl, xr].pack('NN')
return(encrypted)
end
def decrypt_block(block)
xl, xr = block.unpack('NN')
xl, xr = decrypt_pair(xl, xr)
decrypted = [xl, xr].pack('NN')
return(decrypted)
end
end
end #--}}}
# idea.rb Richard Kernahan
# IDEA (International Data Encryption Algorithm) by
# Xuejia Lai and James Massey (1992). Refer to license info at end.
# Ported by Richard Kernahan 2005
module Crypt #--{{{
class IDEA
#require 'crypt/cbc'
include Crypt::CBC
require 'digest/md5'
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.new(key128).digest
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 mulInv(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] = mulInv(encrypt_keys.shift)
decrypt_keys[49] = (-encrypt_keys.shift) % USHORT
decrypt_keys[50] = (-encrypt_keys.shift) % USHORT
decrypt_keys[51] = mulInv(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] = mulInv(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] = mulInv(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)
twoLongs = result.pack('nnnn').unpack('NN')
return(twoLongs)
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 #--}}}
# 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.
# crypt/rattle.rb Richard Kernahan
# add_noise - take a message and intersperse noise to make a new noisy message of given byte-length
# remove_noise - take a noisy message and extract the message
module Crypt #--{{{
module Noise
def add_noise(newLength)
message = self
usableNoisyMessageLength = newLength / 9 * 8
bitmapSize = newLength / 9
remainingBytes = newLength - usableNoisyMessageLength - bitmapSize
if (message.length > usableNoisyMessageLength)
minimumNewLength = (message.length / 8.0).ceil * 9
puts "For a clear text of #{message.length} bytes, the minimum obscured length"
puts "is #{minimumNewLength} bytes which allows for no noise in the message."
puts "You should choose an obscured length of at least double the clear text"
puts "length, such as #{message.length / 8 * 32} bytes"
raise "Insufficient length for noisy message"
end
bitmap = []
usableNoisyMessageLength.times { bitmap << false }
srand(Time.now.to_i)
positionsSelected = 0
while (positionsSelected < message.length)
positionTaken = rand(usableNoisyMessageLength)
if bitmap[positionTaken]
next
else
bitmap[positionTaken] = true
positionsSelected = positionsSelected.next
end
end
noisyMessage = ""
0.upto(bitmapSize-1) { |byte|
c = 0
0.upto(7) { |bit|
c = c + (1<= @sio_string.length }
end
def fcntl(integer_cmd, arg)
raise NotImplementedError, "The fcntl() function is unimplemented on this machine", caller
end
def fileno
nil
end
def flush
self
end
def fsync
0
end
def getc
requireReadable
char = @sio_string[@sio_pos]
@sio_pos += 1 unless char.nil?
char
end
def gets(sep_string=$/)
requireReadable
@sio_lineno += 1
pstart = @sio_pos
@sio_pos = @sio_string.index(sep_string, @sio_pos) || [@sio_string.length, @sio_pos].max
@sio_string[pstart..@sio_pos]
end
def initialize(string="", mode="r+")
@sio_string = string.to_s
@sio_lineno = 0
@mode = mode
@relay = nil
case mode.delete("b")
when "r"
@sio_closed_read = false
@sio_closed_write = true
@sio_pos = 0
when "r+"
@sio_closed_read = false
@sio_closed_write = false
@sio_pos = 0
when "w"
@sio_closed_read = true
@sio_closed_write = false
@sio_pos = 0
@sio_string.replace("")
when "w+"
@sio_closed_read = false
@sio_closed_write = false
@sio_pos = 0
@sio_string.replace("")
when "a"
@sio_closed_read = true
@sio_closed_write = false
@sio_pos = @sio_string.length
when "a+"
@sio_closed_read = false
@sio_closed_write = false
@sio_pos = @sio_string.length
else
raise ArgumentError, "illegal access mode #{mode}", caller
end
end
def isatty
flase
end
def length
@sio_string.length
end
def lineno
@sio_lineno
end
def lineno=(integer)
@sio_lineno = integer
end
def path
nil
end
def pid
nil
end
def pos
@sio_pos
end
def pos=(integer)
raise Errno::EINVAL, "Invalid argument", caller if integer < 0
@sio_pos = integer
end
def print(*args)
requireWritable
args.unshift($_) if args.empty
args.each { |obj| write(obj) }
write($\) unless $\.nil?
nil
end
def printf(format_string, *args)
requireWritable
write format(format_string, *args)
nil
end
def putc(obj)
requireWritable
write(obj.is_a?(Numeric) ? sprintf("%c", obj) : obj.to_s[0..0])
obj
end
def puts(*args)
requireWritable
args.unshift("") if args.empty?
args.each { |obj|
write obj
write $/
}
nil
end
def read(length=nil, buffer=nil)
requireReadable
len = length || [@sio_string.length - @sio_pos, 0].max
raise ArgumentError, "negative length #{len} given", caller if len < 0
buffer ||= ""
pstart = @sio_pos
@sio_pos += len
buffer.replace(@sio_string[pstart..@sio_pos])
buffer.empty? && !length.nil? ? nil : buffer
end
def readchar
requireReadable
raise EOFError, "End of file reached", caller if eof?
getc
end
def readline
requireReadable
raise EOFError, "End of file reached", caller if eof?
gets
end
def readlines(sep_string=$/)
requireReadable
raise EOFError, "End of file reached", caller if eof?
rc = []
until eof
rc << gets(sep_string)
end
rc
end
def reopen(string, mode=nil)
if string.is_a?(self.class) then
raise ArgumentError, "wrong number of arguments (2 for 1)", caller if !mode.nil?
@relay = string
instance_eval(%Q{
class << self
@@relayMethods.each { |name|
define_method(name, ObjectSpace._id2ref(#{@relay.object_id}).method(("original_" + name.to_s).to_sym).to_proc)
}
end
})
else
raise ArgumentError, "wrong number of arguments (1 for 2)", caller if mode.nil?
class << self
@@relayMethods.each { |name|
alias_method(name, "original_#{name}".to_sym)
public name
}
@relay = nil
end unless @relay.nil?
@sio_string = string.to_s
@mode = mode
end
end
def rewind
@sio_pos = 0
@sio_lineno = 0
end
def seek(amount, whence=SEEK_SET)
if whence == SEEK_CUR then
offset += @sio_pos
elsif whence == SEEK_END then
offset += size
end
@sio_pos = offset
end
def string
@sio_string
end
def string=(newstring)
@sio_string = newstring
end
def sync
true
end
def sync=(boolean)
boolean
end
def sysread(length=nil, buffer=nil)
requireReadable
raise EOFError, "End of file reached", caller if eof?
read(length, buffer)
end
def syswrite(string)
requireWritable
addition = "\000" * (@sio_string.length - @sio_pos) + string.to_s
@sio_string[@sio_pos..(addition.length - 1)] = addition
@sio_pos += addition.size
addition.size
end
#In ruby 1.8.4 truncate differs from the docs in two ways.
#First, if an integer greater that the length is given then the string is expanded to the new integer
#length. As this expansion seems to contain junk characters instead of nulls I suspect this may be a
#flaw in the C code which could cause a core dump if abused/used.
#Second, the documentation states that truncate returns 0. It returns the integer instead.
#This implementation follows the documentation in the first instance as I suspect this will be fixed
#in the C code. In the second instance, it follows the actions of the C code instead of the docs.
#This was decided as it causes no immedeate harm and this ruby implentation is to be as compatable
#as possible with the C version. Should the C version change to match the docs the ruby version
#will be simple to update as well.
def truncate(integer)
requireWritable
raise Errno::EINVAL, "Invalid argument - negative length", caller if integer < 0
@sio_string[[integer, @sio_string.length].max..-1] = ""
integer
end
def ungetc(integer)
requireWritable
if @sio_pos > 0 then
@sio_pos -= 1
putc(integer)
@sio_pos -= 1
end
end
alias :each_line :each
alias :eof? :eof
alias :size :length
alias :tty? :isatty
alias :tell :pos
alias :write :syswrite
protected
@@relayMethods.each { |name|
alias_method("original_#{name}".to_sym, name)
protected "original_#{name}".to_sym
}
private
def requireReadable
raise IOError, "not opened for reading", caller[1..-1] if @sio_closed_read
end
def requireWritable
raise IOError, "not opened for writing", caller[1..-1] if @sio_closed_write
end
def requireOpen
raise IOError, "closed stream", caller[1..-1] if @sio_closed_read && @sio_closed_write
end
end
end #--}}}
# rijndael-tables.rb Richard Kernahan
module Crypt #--{{{
module RijndaelTables
LogTable = [
0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3,
100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193,
125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120,
101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142,
150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56,
102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16,
126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186,
43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87,
175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232,
44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160,
127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183,
204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157,
151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209,
83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171,
68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165,
103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7
]
AlogTable = [
1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53,
95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170,
229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49,
83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205,
76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136,
131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154,
181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163,
254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160,
251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65,
195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117,
159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128,
155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84,
252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202,
69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14,
18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23,
57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1
]
S = [
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
]
Si = [
82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251,
124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203,
84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78,
8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37,
114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146,
108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132,
144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6,
208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107,
58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115,
150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110,
71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27,
252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244,
31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95,
96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239,
160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125,
]
IG = [
[0x0e, 0x09, 0x0d, 0x0b],
[0x0b, 0x0e, 0x09, 0x0d],
[0x0d, 0x0b, 0x0e, 0x09],
[0x09, 0x0d, 0x0b, 0x0e]
]
Rcon = [
0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
]
Shifts = [
[
[0, 0],
[1, 3],
[2, 2],
[3, 1]
], [
[0, 0],
[1, 5],
[2, 4],
[3, 3]
], [
[0, 0],
[1, 7],
[3, 5],
[4, 4]
]
]
end
end #--}}}
# rijndael.rb Richard Kernahan
# Adapted from the reference C implementation:
# rijndael-alg-ref.c v2.2 March 2002
# Reference ANSI C code
# authors: Paulo Barreto and Vincent Rijmen
# This code is placed in the public domain.
module Crypt #--{{{
class Rijndael
#require 'crypt/cbc'
include Crypt::CBC
#require 'crypt/rijndael-tables'
include Crypt::RijndaelTables
def initialize(userKey, keyBits = 256, blockBits = 128)
case keyBits
when 128
@keyWords = 4
when 192
@keyWords = 6
when 256
@keyWords = 8
else raise "The key must be 128, 192, or 256 bits long."
end
case (keyBits >= blockBits) ? keyBits : blockBits
when 128
@rounds = 10
when 192
@rounds = 12
when 256
@rounds = 14
else raise "The key and block sizes must be 128, 192, or 256 bits long."
end
case blockBits
when 128
@blockSize = 16
@blockWords = 4
@shiftIndex = 0
when 192
@blockSize = 24
@blockWords = 6
@shiftIndex = 1
when 256
@blockSize = 32
@blockWords = 8
@shiftIndex = 2
else raise "The block size must be 128, 192, or 256 bits long."
end
uk = userKey.unpack('C'*userKey.length)
maxUsefulSizeOfUserKey = (keyBits/8)
uk = uk[0..maxUsefulSizeOfUserKey-1] # truncate
padding = 0
if (userKey.length < keyBits/8)
shortfallInUserKey = (keyBits/8 - userKey.length)
shortfallInUserKey.times { uk << padding }
end
@key = [[], [], [], []]
0.upto(uk.length-1) { |pos|
@key[pos % 4][pos / 4] = uk[pos]
}
@roundKeys = generate_key_schedule(@key, keyBits, blockBits)
end
def block_size
return(@blockSize) # needed for CBC
end
def mul(a, b)
if ((a ==0) | (b == 0))
result = 0
else
result = AlogTable[(LogTable[a] + LogTable[b]) % 255]
end
return(result)
end
def add_round_key(blockArray, roundKey)
0.upto(3) { |i|
0.upto(@blockWords) { |j|
blockArray[i][j] ^= roundKey[i][j]
}
}
return(blockArray)
end
def shift_rows(blockArray, direction)
tmp = []
1.upto(3) { |i| # row zero remains unchanged
0.upto(@blockWords-1) { |j|
tmp[j] = blockArray[i][(j + Shifts[@shiftIndex][i][direction]) % @blockWords]
}
0.upto(@blockWords-1) { |j|
blockArray[i][j] = tmp[j]
}
}
return(blockArray)
end
def substitution(blockArray, sBox)
# replace every byte of the input with the byte at that position in the S-box
0.upto(3) { |i|
0.upto(@blockWords-1) { |j|
blockArray[i][j] = sBox[blockArray[i][j]]
}
}
return(blockArray)
end
def mix_columns(blockArray)
mixed = [[], [], [], []]
0.upto(@blockWords-1) { |j|
0.upto(3) { |i|
mixed[i][j] = mul(2,blockArray[i][j]) ^
mul(3,blockArray[(i + 1) % 4][j]) ^
blockArray[(i + 2) % 4][j] ^
blockArray[(i + 3) % 4][j]
}
}
return(mixed)
end
def inverse_mix_columns(blockArray)
unmixed = [[], [], [], []]
0.upto(@blockWords-1) { |j|
0.upto(3) { |i|
unmixed[i][j] = mul(0xe, blockArray[i][j]) ^
mul(0xb, blockArray[(i + 1) % 4][j]) ^
mul(0xd, blockArray[(i + 2) % 4][j]) ^
mul(0x9, blockArray[(i + 3) % 4][j])
}
}
return(unmixed)
end
def generate_key_schedule(k, keyBits, blockBits)
tk = k[0..3][0..@keyWords-1] # using slice to get a copy instead of a reference
keySched = []
(@rounds + 1).times { keySched << [[], [], [], []] }
t = 0
j = 0
while ((j < @keyWords) && (t < (@rounds+1)*@blockWords))
0.upto(3) { |i|
keySched[t / @blockWords][i][t % @blockWords] = tk[i][j]
}
j += 1
t += 1
end
# while not enough round key material collected, calculate new values
rconIndex = 0
while (t < (@rounds+1)*@blockWords)
0.upto(3) { |i|
tk[i][0] ^= S[tk[(i + 1) % 4][@keyWords - 1]]
}
tk[0][0] ^= Rcon[rconIndex]
rconIndex = rconIndex.next
if (@keyWords != 8)
1.upto(@keyWords - 1) { |j|
0.upto(3) { |i|
tk[i][j] ^= tk[i][j-1];
}
}
else
1.upto(@keyWords/2 - 1) { |j|
0.upto(3) { |i|
tk[i][j] ^= tk[i][j-1]
}
}
0.upto(3) { |i|
tk[i][@keyWords/2] ^= S[tk[i][@keyWords/2 - 1]]
}
(@keyWords/2 + 1).upto(@keyWords - 1) { |j|
0.upto(3) { |i|
tk[i][j] ^= tk[i][j-1]
}
}
end
j = 0
while ((j < @keyWords) && (t < (@rounds+1) * @blockWords))
0.upto(3) { |i|
keySched[t / @blockWords][i][t % @blockWords] = tk[i][j]
}
j += 1
t += 1
end
end
return(keySched)
end
def encrypt_byte_array(blockArray)
blockArray = add_round_key(blockArray, @roundKeys[0])
1.upto(@rounds - 1) { |round|
blockArray = substitution(blockArray, S)
blockArray = shift_rows(blockArray, 0)
blockArray = mix_columns(blockArray)
blockArray = add_round_key(blockArray, @roundKeys[round])
}
# special round without mix_columns
blockArray = substitution(blockArray,S)
blockArray = shift_rows(blockArray,0)
blockArray = add_round_key(blockArray, @roundKeys[@rounds])
return(blockArray)
end
def encrypt_block(block)
raise "block must be #{@blockSize} bytes long" if (block.length() != @blockSize)
blockArray = [[], [], [], []]
0.upto(@blockSize - 1) { |pos|
blockArray[pos % 4][pos / 4] = block[pos]
}
encryptedBlock = encrypt_byte_array(blockArray)
encrypted = ""
0.upto(@blockSize - 1) { |pos|
encrypted << encryptedBlock[pos % 4][pos / 4]
}
return(encrypted)
end
def decrypt_byte_array(blockArray)
# first special round without inverse_mix_columns
# add_round_key is an involution - applying it a second time returns the original result
blockArray = add_round_key(blockArray, @roundKeys[@rounds])
blockArray = substitution(blockArray,Si) # using inverse S-box
blockArray = shift_rows(blockArray,1)
(@rounds-1).downto(1) { |round|
blockArray = add_round_key(blockArray, @roundKeys[round])
blockArray = inverse_mix_columns(blockArray)
blockArray = substitution(blockArray, Si)
blockArray = shift_rows(blockArray, 1)
}
blockArray = add_round_key(blockArray, @roundKeys[0])
return(blockArray)
end
def decrypt_block(block)
raise "block must be #{@blockSize} bytes long" if (block.length() != @blockSize)
blockArray = [[], [], [], []]
0.upto(@blockSize - 1) { |pos|
blockArray[pos % 4][pos / 4] = block[pos]
}
decryptedBlock = decrypt_byte_array(blockArray)
decrypted = ""
0.upto(@blockSize - 1) { |pos|
decrypted << decryptedBlock[pos % 4][pos / 4]
}
return(decrypted)
end
end
end #--}}}
# stringxor.rb Richard Kernahan
module Crypt #--{{{
module StringXor
def ^(aString)
a = self.unpack('C'*(self.length))
b = aString.unpack('C'*(aString.length))
if (b.length < a.length)
(a.length - b.length).times { b << 0 }
end
xor = ""
0.upto(a.length-1) { |pos|
x = a[pos] ^ b[pos]
xor << x.chr()
}
return(xor)
end
end
end
class String
include Crypt::StringXor
end #--}}}
#--}}}
}
__END__
class RaptchaController < ApplicationController
def index # the image responder
Raptcha.render self, params
end
def form # sample on how to use
render :inline => <<-html
valid:#{ Raptcha.valid? params }
html
end
def inline # does not work in older internet exploders
render :inline => <<-html
valid:#{ Raptcha.valid? params }
html
end
end