Nmap Development mailing list archives

Re: Ref:Using NSE OpenSSL for Blowfish?


From: David Fifield <david () bamsoftware com>
Date: Sun, 28 Dec 2008 09:17:04 -0700

On Sat, Dec 27, 2008 at 09:48:23PM -0600, Ron wrote:
Omar Herrera wrote:
I'm not familiar with NSE's OpenSSL module, but i think I know what
might be causing the problem: the Initialization Vector.

I couldn't find in the module's documentation the encryption mode used,
but I'm assuming its CBC. Blowfish does operate on 64 bit blocks, but in
CBC mode the result of encrypting each block is also used to modify the
encryption process of the next block. That is why you can't decipher
blocks independently unless you use ECB mode.

That's incredibly helpful, thanks! I gave up working on this for today
(too tired/frustrated to be productive).

A question, though: the IV you're talking about, is that also the key?
Or is there a separate key and IV? The data I'm using is encrypted in C,
and the interface looks like this:
--
void Blowfish_Init(BLOWFISH_CTX *ctx, unsigned char *key, int keyLen);
void Blowfish_Encrypt(BLOWFISH_CTX *ctx, unsigned long *xl, unsigned
long *xr);
void Blowfish_Decrypt(BLOWFISH_CTX *ctx, unsigned long *xl, unsigned
long *xr);
--

So I only see a key, unless the IV is hardcoded into the library.

The Kocher Blowfish code, it appears, does only raw encryption and
decryption of single blocks, and doesn't support an IV. (An IV would be
used at a higher level of abstraction, like when enrypting a whole
file.) However, because of the way the IV is used in CBC mode, not
having an IV is the same as using an IV of 0x0000000000000000. So you
should be able to make it work by passing a block of zero bytes in as
the iv parameter to openssl.encrypt.

But there appears to be bug in l_encrypt that would keep this from
working:

  const unsigned char *iv = (unsigned char *) luaL_optstring( L, 3, "");
  EVP_EncryptInit_ex( &cipher_ctx, evp_cipher, NULL, key, *iv ? iv : NULL )

That code checks for the optional parameter iv and sets it to "" if not
given. Then, the code checks the first byte of iv to see if it's \0, and
if it is it sends NULL as the IV. From looking at the OpenSSL source
code and from http://www.mail-archive.com/openssl-dev () openssl org/msg08882.html
it seems that when NULL is passed for the IV then its value is just
uninitialized memory(!).

There are two problems with this NSE encryption code. One is that an IV
may legitimately begin with a zero byte, like 0x0011223344556677. The
above code should rather be

  const unsigned char *iv = (unsigned char *) luaL_optstring( L, 3, NULL);
  EVP_EncryptInit_ex( &cipher_ctx, evp_cipher, NULL, key, iv)

The other problem is that the code doesn't protect against OpenSSL
reading outside of allocated memory. If you call openssl.encrypt with an
encryption key or IV shorter than what is expected by the cipher,
OpenSSL will read past the end of those allocated strings. Like
openssl.encrypt"blowfish", "a", "b", data). The length of both the key
and IV should be recorded (in other words using lstrings rather than
strings) and compared to what is expected by the cipher. The functions
EVP_CIPHER_key_length and EVP_CIPHER_iv_length give the expected
lengths.

Does anyone care to fix these two problems? Neither one is hard. Fixing
the first will allow Ron to continue (if the IV is the only problem).
Fixing the second problem avoids a possible crash and minor information
disclosure (potential but unlikely in both cases). As for bounds
checking, I think it's good security practice to fail hard when one of
the parameters is the wrong length; in other words don't truncate a long
key or pad a short key with zeroes.

David Fifield

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org


Current thread: