Hello there! I need to mimic what MySQL does when encrypting and decrypting strings using built-in functions AES_ENCRYPT() and AES_DECRYPT(). Even though the application I am writing is a Rails application, I think this question suited here better because, the encryption will take place in Ruby and not necessarily depends on Rails. I have read a couple of blog posts and apparently MySQL uses AES 128-bit encryption for those functions. On top of that, since this encryption requires a 16-bit key, MySQL pads the string with x0 chars (\0s) until it's 16-bit in size. The algorithm in C from MySQL source code is spotted here: http://gtowey.blogspot.com/2009/01/mysql-aes-encry... I have even tried to examine MySQL's C source code, but that didn't help me much, since I can't really program in C. Maybe someone with a little more experience can have some insights. The source code that implements the encryption (rijndaelKeySetupEnc) and decryption (rijndaelKeySetupDec) functions is here: http://pastie.org/425070 And the actual AES_ENCRYPT (function my_aes_encrypt) and AES_DECRYPT (my_aes_decrypt) source code is here: http://pastie.org/425073 Please note that the necessity of using MySQL's compliancy was not my call and is not a choice. I need that in order to communicate properly with a legacy application, and I don't "own" this database. Please take into consideration that security is definitely not the goal, talking to that system properly is. The key length was not chosen by me and I know it's a little peculiar, as you'll see below, on my replication "script". Now I need to replicate what MySQL does in a Rails application, but every single thing I tried, doesn't work. Here's a way to replicate the behavior I am getting (in this case, using Rails): 1) Create a new Rails app rails encryption-test cd encryption-test 2) Create a new scaffolding script/generate scaffold user name:string password:binary 3) Edit your config/database.yml and add a test MySQL database development: adapter: mysql host: localhost database: test user: <<user>> password: <<password>> 4) Run the migration rake db:migrate 5) Enter console, create an user and update its password from MySQL query script/console Loading development environment (Rails 2.2.2) >> User.create(:name => "John Doe") >> key = "82pjd12398JKBSDIGUSisahdoahOUASDHsdapdjqwjeASIduAsdh078asdASD087asdADSsdjhA7809asdajhADSs" >> ActiveRecord::Base.connection.execute("UPDATE users SET password = AES_ENCRYPT('password', '#{key}') WHERE name='John Doe'") That's where I got stuck. If I attempt to decrypt it, using MySQL it works: >> loaded_user = User.find_by_sql("SELECT AES_DECRYPT(password, '#{key}') AS password FROM users WHERE id=1").first >> loaded_user['password'] => "password" However if I attempt to use OpenSSL library, there's no way I can make it work: cipher = OpenSSL::Cipher::Cipher.new("AES-128-ECB") cipher.padding = 0 cipher.key = key cipher.decrypt user = User.find(1) cipher.update(user.password) << cipher.final #=> "########gf####\027\227" I have tried padding the key: desired_length = 16 * ((key.length / 16) + 1) padded_key = key + "\0" * (desired_length - key.length) cipher = OpenSSL::Cipher::Cipher.new("AES-128-ECB") cipher.key = key cipher.decrypt user = User.find(1) cipher.update(user.password) << cipher.final #=> ""|\e\261\205:\032s\273\242\030\261\272P##" But it really doesn't work. Does anyone have a clue on how can I properly mimic whatever MySQL is doing in Ruby? Thanks a lot for your help. Cheers, -- Felipe.
on 2009-03-24 04:25
on 2009-03-24 04:28
One additional information: You may find weird that I tried padding the key, and even using \000 char to pad it. The reasoning behind it is the way MySQL documents those two functions: "AES_ENCRYPT() and AES_DECRYPT() allow encryption and decryption of data using the official AES (Advanced Encryption Standard) algorithm, previously known as “Rijndael.†Encoding with a 128-bit key length is used, but you can extend it up to 256 bits by modifying the source. We chose 128 bits because it is much faster and it is secure enough for most purposes. AES_ENCRYPT() encrypts a string and returns a binary string. AES_DECRYPT() decrypts the encrypted string and returns the original string. The input arguments may be any length. If either argument is NULL, the result of this function is also NULL. Because AES is a block-level algorithm, padding is used to encode uneven length strings and so the result string length may be calculated using this formula: 16 × (trunc(string_length / 16) + 1) If AES_DECRYPT() detects invalid data or incorrect padding, it returns NULL. However, it is possible for AES_DECRYPT() to return a non-NULL value (possibly garbage) if the input data or the key is invalid." Hope that also helps. Thanks again. -- Felipe
on 2009-03-24 04:47
On Mar 23, 2009, at 11:25 PM, Felipe Coury wrote: > Because AES is a block-level algorithm, padding is used to encode > uneven > length strings and so the result string length may be calculated using > this formula: > > 16 × (trunc(string_length / 16) + 1) Do you mean to have: 16 * (string_length + 15)/16 If the string length is 32, what do you expect the result to be? Your formula gives 48, (16*(trunc(32/16)+1))==(16*(2+1)), while mine gives 32, (16*(32+15)/16)==(16*(47/16))==(16*2) [integer division]. Here's a bit of code that I've lifted out of another project: # Encrypt the content of the document, block by block, in a manner # compatible with the original Python (so we can decrypt it and # remain backwardly compatible) rijndael = Crypt::Rijndael.new(self.key, 256, 256) encryptedData = "" data << 'X' # a marker added to cope with partial block blocks, bytes = data.length.divmod(32) unless bytes.zero? data << "\0" * (32 - bytes) blocks += 1 end (0...blocks).each do |block| encryptedData << rijndael.encrypt_block(data[block * 32, 32]) end The decrypting side was Java and I don't know why the 'X' was chosen (seems that I recall something about there being a byte with the number of extra bytes of padding... or your formula might hold a clue). Anyway, you'd have to adjust it for 128-bit/16-byte keys (and blocks). -Rob Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com
on 2009-03-24 05:35
On 24 Mar, 04:21, Felipe Coury <felipe.co...@gmail.com> wrote: > cipher.key = key > cipher.decrypt > > user = User.find(1) > cipher.update(user.password) << cipher.final #=> > "########gf####\027\227" > I use the following code for encrypt/decrypt: @cipherAES256=OpenSSL::Cipher::AES256.new("CBC") if @cipherAES256.nil? @cipherAES256.encrypt @cipherAES256.key=key ct = @cipherAES256.update(plainPassword) + @cipherAES256.final password=ct.unpack("H*")[0] @cipherAES256=OpenSSL::Cipher::AES256.new("CBC") if @cipherAES256.nil? @cipherAES256.decrypt @cipherAES256.key=key ct = @cipherAES256.update([password].pack("H*")) + @cipherAES256.final I don't know if it can helps you (it uses 256 and CBC), try changing your code from cipher.update(user.password) << cipher.final to cipher.update([user.password].pack("H*")) << cipher.final Giovanni
on 2009-03-24 06:34
Giovanni / Rob, Thanks a lot for your responses, really. Unfortunately, it it still doesn't work. I tried what you both suggested, take a look at this console transcript: >> def aes(m,k,t) >> (aes = OpenSSL::Cipher::AES128.new("ECB").send(m)).key = k >> aes.update(t) << aes.final >> end => nil >> ?> def encrypt(key, text) >> aes(:encrypt, key, text) >> end => nil >> ?> def decrypt(key, text) >> aes(:decrypt, key, text) >> end => nil >> key = "82pjd12398JKBSDIGUSisahdoahOUASDHsdapdjqwjeASIduAsdh078asdASD087asdADSsdjhA7809asdajhADSs" => "82pjd12398JKBSDIGUSisahdoahOUASDHsdapdjqwjeASIduAsdh078asdASD087asdADSsdjhA7809asdajhADSs" >> u = User.find(1) => #<User id: 1, name: "John Doe", password: "###\270##\206ή5\202?\003\021###", created_at: "2009-03-23 20:31:43", updated_at: "2009-03-23 20:31:43"> >> u.password.length => 16 >> decrypt(key, u.password) OpenSSL::CipherError: bad decrypt from (irb):8:in `final' from (irb):8:in `aes' from (irb):16:in `decrypt' from (irb):19 >> decrypt(key, [u.password].pack("H*")) OpenSSL::CipherError: wrong final block length from (irb):8:in `final' from (irb):8:in `aes' from (irb):16:in `decrypt' from (irb):32 >> [u.password].pack("H*").length => 8 >> card = ([u.password].pack("H*") + ("\0" * 8)) => "9##n###\005\000\000\000\000\000\000\000\000" >> decrypt(key, card) OpenSSL::CipherError: bad decrypt from (irb):8:in `final' from (irb):8:in `aes' from (irb):16:in `decrypt' from (irb):43 Any other ideas? Thanks, -- Felipe
on 2009-03-24 07:30
Some more discoveries... According to the blog post I sent before, here's how MySQL works with the key you provide AES_ENCRYPT / DECRYPT: "The algorithm just creates a 16 byte buffer set to all zero, then loops through all the characters of the string you provide and does an assignment with bitwise OR between the two values. If we iterate until we hit the end of the 16 byte buffer, we just start over from the beginning doing ^=. For strings shorter than 16 characters, we stop at the end of the string." I don't know if you can read C, but here's the mentioned snippet: http://pastie.org/425161 Specially this part: bzero((char*) rkey,AES_KEY_LENGTH/8); /* Set initial key */ for (ptr= rkey, sptr= key; sptr < key_end; ptr++,sptr++) { if (ptr == rkey_end) ptr= rkey; /* Just loop over tmp_key until we used all key */ *ptr^= (uint8) *sptr; } So I came up with this method: def mysql_key(key) # The algorithm just creates a 16 byte buffer set to all zero, final_key = "\0" * 16 # Number of string "blocks" t = key.length / 16 t.times do |i| # For each block key_block = key[i*16, 16] # Runs bitwise XOR for each char on string # and the same char on the block 16.times do |j| final_key[j] ^= key_block[j] end end final_key end But it still fails: >> key = "82pjd12398JKBSDIGUSisahdoahOUASDHsdapdjqwjeASIduAsdh078asdASD087asdADSsdjhA7809asdajhADSs" => "82pjd12398JKBSDIGUSisahdoahOUASDHsdapdjqwjeASIduAsdh078asdASD087asdADSsdjhA7809asdajhADSs" >> mkey = mysql_key(key) => "\027\024GK\023P{#8?G!8[r." >> mkey.length => 16 >> decrypt(mkey, User.find(1).password) User Load (11.3ms) SELECT * FROM `users` WHERE (`users`.`id` = 1) OpenSSL::CipherError: bad decrypt from (irb):4:in `final' from (irb):4:in `aes' from (irb):12:in `decrypt' from (irb):42 >> decrypt(mkey, [User.find(1).password].pack("H*")) User Load (2.8ms) SELECT * FROM `users` WHERE (`users`.`id` = 1) OpenSSL::CipherError: wrong final block length from (irb):4:in `final' from (irb):4:in `aes' from (irb):12:in `decrypt' from (irb):43 Question is: did I miss something :) ? I have a feeling I am *almost* there... Thanks again! -- Felipe
on 2009-03-24 07:38
Just as a FYI, it works!!!
I forgot about the remains... Take a look at the final incarnation:
def mysql_key(key)
# The algorithm just creates a 16 byte buffer set to all zero,
final_key = "\0" * 16
# Number of string "blocks"
blocks, remain = key.length.divmod(16)
blocks.times do |i|
# For each block
key_block = key[i*16, 16]
# Runs bitwise XOR for each char on string
# and the same char on the block
16.times do |j|
final_key[j] ^= key_block[j]
end
end
if remain
remain.times do |i|
final_key[i] ^= key[(blocks * 16) + i]
end
end
final_key
end
And:
>> mkey = mysql_key(key)
=> "dp&!{\021?pK?G!8[r."
>> decrypt(mkey, User.find(1).password)
User Load (2.9ms) SELECT * FROM `users` WHERE (`users`.`id` = 1)
=> "password"
Just BEATIFUL!
Thanks a lot everyone!
on 2009-03-24 08:56
On Mar 24, 2009, at 2:35 AM, Felipe Coury wrote: > > > > Posted via http://www.ruby-forum.com/. > I'm glad you got it. Your key-building function doesn't need to be quite so complex: def mysql_key2(key) final_key = "\0" * 16 key.length.times do |i| final_key[i%16] ^= key[i] end final_key end Hardly needs any comments now ;-) Just a pointer to the MySQL doc perhaps. irb> mkey2 = mysql_key2(key) => "dp&!{\021?pK?G!8[r." irb> mkey == mkey2 => true -Rob Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com
on 2009-03-24 14:36
Rob Biedenharn wrote: > I'm glad you got it. Your key-building function doesn't need to be > quite so complex: Rob, you nailed it. Thanks a lot! Best regards, -- Felipe
on 2010-07-01 17:34
Having no luck with this. Getting the following error when generating they key in 1.8.7 and 1.9.1. Any help would be much appreciated. ruby-1.9.1-p378 > key = "test_key" => "test_key" ruby-1.9.1-p378 > final_key = "\0" * 16 => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" ruby-1.9.1-p378 > key.length.times do |i| ruby-1.9.1-p378 > final_key[i%16] ^= key[i] ruby-1.9.1-p378 ?> end NoMethodError: undefined method `^' for "\x00":String from (irb):89:in `block in irb_binding' from (irb):88:in `times' from (irb):88 ruby-1.9.1-p378 > final_key => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" Rob Biedenharn wrote: > On Mar 24, 2009, at 2:35 AM, Felipe Coury wrote: >> >> >> >> Posted via http://www.ruby-forum.com/. >> > > > I'm glad you got it. Your key-building function doesn't need to be > quite so complex: > > def mysql_key2(key) > final_key = "\0" * 16 > key.length.times do |i| > final_key[i%16] ^= key[i] > end > final_key > end > > Hardly needs any comments now ;-) Just a pointer to the MySQL doc > perhaps. > > irb> mkey2 = mysql_key2(key) > => "dp&!{\021?pK?G!8[r." > irb> mkey == mkey2 > => true > > -Rob > > Rob Biedenharn http://agileconsultingllc.com > Rob@AgileConsultingLLC.com
on 2010-07-01 18:30
On Jul 1, 2010, at 11:34 AM, Joshua Mckinney wrote: >> final_key[i%16] ^= key[i] >> => true > ruby-1.9.1-p378 > key = "test_key" > > ruby-1.9.1-p378 > final_key > => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" Because in Ruby 1.8.6, "hello"[0] is 104, but in 1.8.7 and 1.9.x, "hello"[0] is "h" Change that line to: final_key[i%16] = (final_key[i%16].ord ^ key[i].ord).chr And you should get the right answer: irb> x="hello" => "hello" irb> x[0] = (x[0].ord ^ 0x20).chr => "H" irb> x => "Hello" String#ord gives the Fixnum value of a single-character string. Fixnum#chr gives the single-character String whose #ord is the Fixnum (I'm sure the actual docs say that better ;-) -Rob Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com http://gaslightsoftware.com rab@GaslightSoftware.com
on 2010-07-01 18:55
Correction: in 1.8.7 no error is produced but the final_key is not correct: ruby-1.8.7-p174 > key = "test key" => "test key" ruby-1.8.7-p174 > final_key = "\0" * 16 => "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" ruby-1.8.7-p174 > key.length.times do |i| ruby-1.8.7-p174 > final_key[i%16] ^= key[i] ruby-1.8.7-p174 ?> end => 8 ruby-1.8.7-p174 > final_key => "test key\000\000\000\000\000\000\000\000" Joshua Mckinney wrote: > Having no luck with this. Getting the following error when generating > they key in 1.8.7 and 1.9.1. Any help would be much appreciated. > > > > ruby-1.9.1-p378 > key = "test_key" > => "test_key" > ruby-1.9.1-p378 > final_key = "\0" * 16 > => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" > ruby-1.9.1-p378 > key.length.times do |i| > ruby-1.9.1-p378 > final_key[i%16] ^= key[i] > ruby-1.9.1-p378 ?> end > NoMethodError: undefined method `^' for "\x00":String > from (irb):89:in `block in irb_binding' > from (irb):88:in `times' > from (irb):88 > > ruby-1.9.1-p378 > final_key > => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" > > > > >
on 2010-07-01 19:01
Thanks for the reply, we got rid of the error in 1.9.1 but both 1.9.1 and 1.8.7 produce the wrong final_key ruby-1.9.1-p378 > final_key => "test key\x00\x00\x00\x00\x00\x00\x00\x00" ruby-1.8.7-p174 > final_key => "test key\000\000\000\000\000\000\000\000" Rob Biedenharn wrote: > On Jul 1, 2010, at 11:34 AM, Joshua Mckinney wrote: >>> final_key[i%16] ^= key[i] >>> => true >> ruby-1.9.1-p378 > key = "test_key" >> >> ruby-1.9.1-p378 > final_key >> => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" > > Because in Ruby 1.8.6, "hello"[0] is 104, but in 1.8.7 and 1.9.x, > "hello"[0] is "h" > > Change that line to: > > final_key[i%16] = (final_key[i%16].ord ^ key[i].ord).chr > > And you should get the right answer: > > irb> x="hello" > => "hello" > irb> x[0] = (x[0].ord ^ 0x20).chr > => "H" > irb> x > => "Hello" > > String#ord gives the Fixnum value of a single-character string. > Fixnum#chr gives the single-character String whose #ord is the Fixnum > > (I'm sure the actual docs say that better ;-) > > -Rob > > Rob Biedenharn > http://agileconsultingllc.com > Rob@AgileConsultingLLC.com > http://gaslightsoftware.com > rab@GaslightSoftware.com
on 2010-07-01 20:40
On Jul 1, 2010, at 1:01 PM, Joshua Mckinney wrote: >> Because in Ruby 1.8.6, "hello"[0] is 104, but in 1.8.7 and 1.9.x, >> irb> x[0] = (x[0].ord ^ 0x20).chr >> > > ruby-1.8.7-p174 > final_key > => "test key\000\000\000\000\000\000\000\000" > > -- > Posted via http://www.ruby-forum.com/. > What final_key do you expect? You need to post the full code and input along with the expected value (or what 1.8.6 gives?) in order to help. -Rob
on 2010-07-01 22:46
I'm here are all the methods for encryption
def mysql_encrypt(s, key)
encrypt(s, mysql_key(key))
end
def mysql_decrypt(s, key)
puts s
decrypt(s, mysql_key(key))
end
protected
def aes(m,k,t)
(aes = OpenSSL::Cipher::AES128.new("ECB").send(m)).key = k
aes.update(t) << aes.final
end
def encrypt(text, key)
aes(:encrypt, key, text)
end
def decrypt(text, key)
aes(:decrypt, key, text)
end
def mysql_key(key)
key = key.encode("UTF-8")
final_key = "\0" * 16
key.length.times do |i|
final_key[i%16] = (final_key[i%16].ord ^ key[i].ord).chr
end
final_key
end
When is use the key set to "test key" and string to be encrypted set to
"Some text for encryption". The returned encrypted string is:
"\x9E\xB6g\xB7\xF0\xF8\x9F
M\xC1\x82\xA0\xFC\xEF[hY\xEC]=\xE6U\xE8o\xFBN\xCD\x929\x9A\xF4\xB5"
But the encrypted string should be:
"9EB667B7F0F89F204DC182A0FCEF5B6859EC5D3DE655E86FFB4ECD92399AF4B5"
(generated from C# mysql_mimic and Mysql itself)
My encrypted string appears some hexadecimal values interlaced and I'm
not sure why or how "decode" it properly to match the desire encryption
results.
The above results were produced in ruby 1.9.1 (which is what we are
using for this project)
Thanks
Rob Biedenharn wrote:
>
> What final_key do you expect? You need to post the full code and
> input along with the expected value (or what 1.8.6 gives?) in order to
> help.
>
> -Rob
on 2010-07-01 23:26
Looks like was I given some skewed information from our C# fella.
"\x9E\xB6g\xB7\xF0\xF8\x9F
M\xC1\x82\xA0\xFC\xEF[hY\xEC]=\xE6U\xE8o\xFBN\xCD\x929\x9A\xF4\xB5".unpack("H*")
= ["9eb667b7f0f89f204dc182a0fcef5b6859ec5d3de655e86ffb4ecd92399af4b5"]
which means everything it is working :-)
My only issue now is taking
"9eb667b7f0f89f204dc182a0fcef5b6859ec5d3de655e86ffb4ecd92399af4b5" and
"packing" it back to "\x9E\xB6g\xB7\xF0\xF8\x9F
M\xC1\x82\xA0\xFC\xEF[hY\xEC]=\xE6U\xE8o\xFBN\xCD\x929\x9A\xF4\xB5"
Anyone know how to do that?
Thanks,
on 2010-07-02 00:11
On Jul 1, 2010, at 5:27 PM, Joshua Mckinney wrote: > "9eb667b7f0f89f204dc182a0fcef5b6859ec5d3de655e86ffb4ecd92399af4b5" and > "packing" it back to "\x9E\xB6g\xB7\xF0\xF8\x9F > M\xC1\x82\xA0\xFC\xEF[hY\xEC]=\xE6U\xE8o\xFBN\xCD\x929\x9A\xF4\xB5" > > Anyone know how to do that? > > Thanks, > -- > Posted via http://www.ruby-forum.com/. > irb> ["9eb667b7f0f89f204dc182a0fcef5b6859ec5d3de655e86ffb4ecd92399af4b5 "].pack("H*") => "\x9E\xB6g\xB7\xF0\xF8\x9F M\xC1\x82\xA0\xFC\xEF[hY\xEC]=\xE6U\xE8o \xFBN\xCD\x929\x9A\xF4\xB5" Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com http://gaslightsoftware.com rab@GaslightSoftware.com
on 2010-07-02 00:38
Awesome, could not find .pack in the 1.9.1 documentation. Everything is
now working.
Here is all the code for 1.9.1:
def mysql_encrypt(s, key=@key)
encrypt(s, mysql_key(key))
end
def mysql_decrypt(s, key=@key)
puts s
decrypt(s, mysql_key(key))
end
protected
def aes(m,k,t)
c = OpenSSL::Cipher::Cipher.new('aes-128-ecb').send(m)
c.key = k
c.update(t) + c.final
end
def encrypt(text, key)
aes(:encrypt, key, text).unpack("H*")
end
def decrypt(text, key)
aes(:decrypt, key, [text].pack("H*"))
end
def mysql_key(key)
final_key = "\0" * 16
key.length.times do |i|
final_key[i%16] = (final_key[i%16].ord ^ key[i].ord).chr
end
final_key
end
Thanks for you help Rob
Rob Biedenharn wrote:
> ["9eb667b7f0f89f204dc182a0fcef5b6859ec5d3de655e86ffb4ecd92399af4b5
> "].pack("H*")
> => "\x9E\xB6g\xB7\xF0\xF8\x9F M\xC1\x82\xA0\xFC\xEF[hY\xEC]=\xE6U\xE8o
> \xFBN\xCD\x929\x9A\xF4\xB5"
>
> Rob Biedenharn
> http://agileconsultingllc.com
> Rob@AgileConsultingLLC.com
> http://gaslightsoftware.com
> rab@GaslightSoftware.com
on 2010-07-02 13:14
Joshua Mckinney wrote:
> Awesome, could not find .pack in the 1.9.1 documentation
It's Array#pack, as opposed to String#unpack.
on 2010-07-02 17:46
Ha..well that would make sense given unpack returns an array. Deductive
reasoning was on the back-burner yesterday.
Made a small change so decrypt returns the string only
The following worked in 1.8.7 and 1.9.1
def mysql_encrypt(s, key)
encrypt(s, mysql_key(key))
end
def mysql_decrypt(s, key)
puts s
decrypt(s, mysql_key(key))
end
protected
def aes(m,k,t)
c = OpenSSL::Cipher::Cipher.new('aes-128-ecb').send(m)
c.key = k
c.update(t) + c.final
end
def encrypt(text, key)
aes(:encrypt, key, text).unpack("H*")[0]
end
def decrypt(text, key)
aes(:decrypt, key, [text].pack("H*"))
end
def mysql_key(key)
final_key = "\0" * 16
key.length.times do |i|
final_key[i%16] = (final_key[i%16].ord ^ key[i].ord).chr
end
final_key
end
Thanks,
Josh
Brian Candler wrote:
> Joshua Mckinney wrote:
>> Awesome, could not find .pack in the 1.9.1 documentation
>
> It's Array#pack, as opposed to String#unpack.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.