Mimic AES_ENCRYPT and AES_DECRYPT functions in Ruby

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:

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.

···

--
Posted via http://www.ruby-forum.com/\.

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

···

--
Posted via http://www.ruby-forum.com/.

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 24 Mar, 04:21, Felipe Coury <felipe.co...@gmail.com> wrote:

Hello there!

I need to mimic what MySQL does when encrypting and decrypting strings
using built-in functions AES_ENCRYPT() and AES_DECRYPT().
...
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"

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 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)

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

···

--
Posted via http://www.ruby-forum.com/\.

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 :slight_smile: ?

I have a feeling I am *almost* there...

Thanks again!

-- Felipe

···

--
Posted via http://www.ruby-forum.com/\.

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!

···

--
Posted via http://www.ruby-forum.com/\.

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!
-- 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 :wink: Just a pointer to the MySQL doc perhaps.

mkey2 = mysql_key2(key)

=> "dp&!{\021?pK?G!8[r."

mkey == mkey2

=> true

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Mar 24, 2009, at 2:35 AM, Felipe Coury wrote:

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

···

--
Posted via http://www.ruby-forum.com/\.

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 :wink: Just a pointer to the MySQL doc
perhaps.

> mkey2 = mysql_key2(key)
=> "dp&!{\021?pK?G!8[r."
> mkey == mkey2
=> true

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

--
Posted via http://www.ruby-forum.com/\.

Rob Biedenharn 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 :wink: Just a pointer to the MySQL doc
perhaps.

> mkey2 = mysql_key2(key)
=> "dp&!{\021?pK?G!8[r."
> mkey == mkey2
=> true

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

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"

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:

x="hello"

=> "hello"

x[0] = (x[0].ord ^ 0x20).chr

=> "H"

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 :wink:

-Rob

Rob Biedenharn

  Rob@AgileConsultingLLC.com

  rab@GaslightSoftware.com

···

On Jul 1, 2010, at 11:34 AM, Joshua Mckinney wrote:

On Mar 24, 2009, at 2:35 AM, Felipe Coury wrote:

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"

--
Posted via http://www.ruby-forum.com/\.

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:

> x="hello"
=> "hello"
> x[0] = (x[0].ord ^ 0x20).chr
=> "H"
> 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 :wink:

-Rob

Rob Biedenharn
http://agileconsultingllc.com
  Rob@AgileConsultingLLC.com
http://gaslightsoftware.com
  rab@GaslightSoftware.com

--
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 Jul 1, 2010, at 1:01 PM, Joshua Mckinney wrote:

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:

> x="hello"
=> "hello"
> x[0] = (x[0].ord ^ 0x20).chr
=> "H"
> 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 :wink:

-Rob

Rob Biedenharn
http://agileconsultingllc.com
Rob@AgileConsultingLLC.com
http://gaslightsoftware.com
rab@GaslightSoftware.com

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"

--
Posted via http://www.ruby-forum.com/\.

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

--
Posted via http://www.ruby-forum.com/\.

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 :slight_smile:

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,

···

--
Posted via http://www.ruby-forum.com/.

["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

  Rob@AgileConsultingLLC.com

  rab@GaslightSoftware.com

···

On Jul 1, 2010, at 5:27 PM, Joshua Mckinney wrote:

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 :slight_smile:

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,
--
Posted via http://www.ruby-forum.com/\.

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

--
Posted via http://www.ruby-forum.com/\.

Joshua Mckinney wrote:

Awesome, could not find .pack in the 1.9.1 documentation

It's Array#pack, as opposed to String#unpack.

···

--
Posted via http://www.ruby-forum.com/\.

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.

--
Posted via http://www.ruby-forum.com/\.