class Crypt::Rijndael
Public Class Methods
new(userKey, keyBits = 256, blockBits = 128)
click to toggle source
# File lib/crypt/rijndael.rb, line 18 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
Public Instance Methods
add_round_key(blockArray, roundKey)
click to toggle source
# File lib/crypt/rijndael.rb, line 86 def add_round_key(blockArray, roundKey) 0.upto(3) { |i| 0.upto(@blockWords) { |j| blockArray[i][j] ^= roundKey[i][j] } } return(blockArray) end
block_size()
click to toggle source
# File lib/crypt/rijndael.rb, line 71 def block_size return(@blockSize) # needed for CBC end
decrypt_block(block)
click to toggle source
# File lib/crypt/rijndael.rb, line 255 def decrypt_block(block) raise "block must be #{@blockSize} bytes long" if (block.length() != @blockSize) blockArray = [[], [], [], []] 0.upto(@blockSize - 1) { |pos| b = block[pos] b = b.ord() unless b.is_a?(Fixnum) # make sure we have a byte, not a single-char string blockArray[pos % 4][pos / 4] = b } decryptedBlock = decrypt_byte_array(blockArray) decrypted = "".force_encoding("ASCII-8BIT") # stop ruby 2 using Unicode 0.upto(@blockSize - 1) { |pos| decrypted << decryptedBlock[pos % 4][pos / 4] } return(decrypted) end
decrypt_byte_array(blockArray)
click to toggle source
# File lib/crypt/rijndael.rb, line 238 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
encrypt_block(block)
click to toggle source
# File lib/crypt/rijndael.rb, line 220 def encrypt_block(block) block = block.force_encoding("ASCII-8BIT") if block.is_a?(String) # affordance raise "block must be #{@blockSize} bytes long" if (block.length() != @blockSize) blockArray = [[], [], [], []] 0.upto(@blockSize - 1) { |pos| b = block[pos] b = b.ord unless b.is_a?(Fixnum) blockArray[pos % 4][pos / 4] = b } encryptedBlock = encrypt_byte_array(blockArray) encrypted = "".force_encoding("ASCII-8BIT") # stop ruby 2 using Unicode 0.upto(@blockSize - 1) { |pos| encrypted << encryptedBlock[pos % 4][pos / 4] } return(encrypted) end
encrypt_byte_array(blockArray)
click to toggle source
# File lib/crypt/rijndael.rb, line 204 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
generate_key_schedule(k, keyBits, blockBits)
click to toggle source
# File lib/crypt/rijndael.rb, line 149 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
inverse_mix_columns(blockArray)
click to toggle source
# File lib/crypt/rijndael.rb, line 135 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
mix_columns(blockArray)
click to toggle source
# File lib/crypt/rijndael.rb, line 121 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
mul(a, b)
click to toggle source
# File lib/crypt/rijndael.rb, line 76 def mul(a, b) if ((a ==0) | (b == 0)) result = 0 else result = AlogTable[(LogTable[a] + LogTable[b]) % 255] end return(result) end
shift_rows(blockArray, direction)
click to toggle source
# File lib/crypt/rijndael.rb, line 96 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
substitution(blockArray, sBox)
click to toggle source
# File lib/crypt/rijndael.rb, line 110 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