openssl compatible key and IV calculation

M

Markus Steinborn

Hello,

I'd like to compute the initialisation vector and the key for decrypting
ciphertexts. The operation I'd like to do can be done with openssl by
the following command:

openssl enc -a -aes-256-cbc -pass pass:"Secret Passphrase" -base64 -P -S
ab001d77079ba218

Obviously "Secret passphrase" is the passphrase and "ab001d77079ba218"
is the salt - we'll assume that both are known.

The goal is to compute the initialisation vector (IV) and the key.


How to do that in perl?

The openssl man-pages and google did not help me.




Thanks

Markus Steinborn
 
J

J. Gleixner

Hello,

I'd like to compute the initialisation vector and the key for decrypting
ciphertexts. The operation I'd like to do can be done with openssl by
the following command:

openssl enc -a -aes-256-cbc -pass pass:"Secret Passphrase" -base64 -P -S
ab001d77079ba218

Obviously "Secret passphrase" is the passphrase and "ab001d77079ba218"
is the salt - we'll assume that both are known.

The goal is to compute the initialisation vector (IV) and the key.


How to do that in perl?

The openssl man-pages and google did not help me.

openssl is a command/executable and the above produces output, so it's
not anything special or different from many other commands. If you
want to execute the command, capture the output, and do something
with it...

use strict;
use warnings;

my $str = `/usr/bin/openssl enc -a -aes-256-cbc -pass pass:"Secret
Passphrase"-base64 -P -S ab001d77079ba218`;

my %fields = $str =~ / (\S+) \s* = \s* (\S+) /xg;

use Data::Dumper;
print Dumper( \%fields );

$VAR1 = {
'salt' => 'AB001D77079BA218',
'iv' => 'B99974A9FF1F39AF888BC378015C37D1',
'key' =>
'A4430C9C6AD9B88836B7277193CC21C56E5503F6F0DBF3E777A31BE7D42765F8'
};
 
M

Markus Steinborn

Hi Gleixner,

thanks for your answer.

J. Gleixner said:
my $str = `/usr/bin/openssl enc -a -aes-256-cbc -pass pass:"Secret
Passphrase"-base64 -P -S ab001d77079ba218`;

Not bad... I'm developinig under Linux, but the hard encoded path might
be a portability problem, especcially on windows (ActiveState Perl 5.16
with Crypt::CBC and Crypt::OpenSSL::AES).

Perhaps there is a trick to use either the OpenSSL system library (on
linux/Unix) or the openSSL library ActiveState Perl uses (on windows).

But anyway: An enviromnent variable poiting to the openssl binary might
help out of this situation - if we do not find anything better.

I just thought that there might be a perl solution like
Crypt::OpenSSL::AES for the encryption/decryption.


Greetings from Germany

Markus
 
J

Jürgen Exner

Markus Steinborn said:
I'd like to compute the initialisation vector and the key for decrypting
ciphertexts. The operation I'd like to do can be done with openssl by
the following command:

openssl enc -a -aes-256-cbc -pass pass:"Secret Passphrase" -base64 -P -S
ab001d77079ba218

Obviously "Secret passphrase" is the passphrase and "ab001d77079ba218"
is the salt - we'll assume that both are known.

The goal is to compute the initialisation vector (IV) and the key.
How to do that in perl?

It looks like you got a working solution already. Is there a specific
reason why you can't just call 'openssl' from you Perl script?

jue
 
M

Markus Steinborn

Jürgen Exner said:
It looks like you got a working solution already. Is there a specific
reason why you can't just call 'openssl' from you Perl script?

Well, I've a weak one: I'd prefer to get rid on openssl dependencies...
There exist Crypt::Rijndael (which might need some fixing). But it's
always nice to have a working fallback - it might happen that I cannot
get rid of OpenSSL.

The problem with openssl is: It is not installed on an average windows
machine.



Markus
 
M

Markus Steinborn

Hi Ben,

Ben said:
Well, have you tried using those two together? I can't see any reason it
shouldn't work. You could also try Crypt::Cipher::AES, which has its own
AES implementation and doesn't depend on OpenSSL.

thanks, that's exactly I'm looking for - noticing that it does not solf
key and IV calculation without openssl, but decrypting without openssl.


Markus
 
M

Markus Steinborn

Ben said:
Well, have you tried using those two together? I can't see any reason it
shouldn't work.

They work fiine tohether under Linux (Windows not tested yet) - but
offer no methood for an openssl compatible key and IV calculation.


Markus
 
M

Markus Steinborn

Hi Ben,

Ben said:
Oh, sorry, I missed the significance of the -P option.

Looking through the source of Crypt::CBC, the key/IV calculation doesn't
depend on either the cipher or the plaintext, and this gives me the same
results as openssl(1):

Wow, you've got it - that is what I've been looking for... and a handy
source code which clearly documents how these values are calculated --
perfect.

I'm testing it in the next few days.


Thanks

Markus
 
C

Charles DeRykus

Well, all I did was pull the code out of Crypt::CBC.

I don't know where this function is specified, but I have to say I'm a
little worried about the unconditional use of MD5. In the Kerberos
world, which I'm more familiar with, this function is called
'string2key' and is considered cryptographically significant. Modern
Kerberos enctypes, in particular the AES enctypes, use a function from
PKCS#5, which uses SHA-1 rather than MD5 and performs many iterations to
increase the cost of a dictionary attack.

If you're using this one-iteration-of-MD5 function for encrypting
anything important, it's probably worth being rather careful to use very
strong passphrases.

openssl will handle SHA so perhaps a very small patch to Crypt::CBC and
the script itself to replace Digest::MD5::md5 with Digest::SHA::sha1
might be another option...
 
R

Rainer Weikusat

[...]
In the Kerberos world, which I'm more familiar with, this function
is called 'string2key' and is considered cryptographically
significant. Modern Kerberos enctypes, in particular the AES
enctypes, use a function from PKCS#5, which uses SHA-1 rather than
MD5 and performs many iterations to increase the cost of a
dictionary attack.

Ehh ... there is no way to do 'a dictionary attack' against Kerberos
because the keys derived from user passphrases are supposed to be kept
secret. There also wouldn't be any point in performing such a
dictionary attack because the key derived from such a passphrase is
what is actually used for authentication: Someone who knows that
doesn't need to know the passphrase.
If you're using this one-iteration-of-MD5 function for encrypting
anything important,

JFTR: The algortihm you posted does 3 rounds of MD5, not one.
 
R

Rainer Weikusat

Markus Steinborn said:
Wow, you've got it - that is what I've been looking for... and a
handy source code which clearly documents how these values are
calculated -- perfect.

Except one minor nit: For algorithms without (known) 'classes of weak
keys' (such as AES), you can as well just use (cryptographically
strong) random numbers (aka 'a sufficient quantity of randomly
generated bytes').
 
R

Rainer Weikusat

Markus Steinborn said:
I'd like to compute the initialisation vector and the key for
decrypting ciphertexts. The operation I'd like to do can be done with
openssl by the following command:

openssl enc -a -aes-256-cbc -pass pass:"Secret Passphrase" -base64 -P
-S
ab001d77079ba218

Obviously "Secret passphrase" is the passphrase and "ab001d77079ba218"
is the salt - we'll assume that both are known.

If you have access to 'a secure channel' which can be used to
communicate two non-random strings which can be turnt into an
encyrption key and initialization vector, why don't you just use a
random key and a random IV and the same 'secure channel' to enable
sender and recipient to share them?
 
R

Rainer Weikusat

Ben Morrow said:
Quoth Charles DeRykus <[email protected]>:
[...]

...that said, I've just looked at the source of 'openssl enc', and there
*is* an apparently-undocumented -md option to choose the hash function
to use for string2key, so it might be possible for the OP to switch to
SHA-1. However, there still isn't an option to add iterations, which is
almost more important.

In the sense that neither one nor the other matters, yes. The hash is
here solely used a 'compression function' capable of turning an
arbitrarily long string into a fixed-size encryption key, not because
of any cryptographic properties it might have. And using a more
'expensive' calculation to derive this key is totally pointless _for
encryption_ because it won't increase the amount of entropy in the
input and once an attacker knows the key, he can decrypt away to his
hearts content without caring about how it was created.

It is not pointless when the derived key is supposed to be used in an
authentication system relying on 'the /etc/passwd fallacy' that no one
will ever be able to figure out the input (password) and thus, be able
to impersonate another using, based on knowing output and algorithm
alone. Or at least 'sort of not pointless': Expensive computations of
today tend to become 'inexpensive computations of tomorrow' quickly
....
 
R

Rainer Weikusat

Ben Morrow said:
Pretty-much any system which relies solely on human-memorable keys is
vulnerable to dictionary attacks. The fact Kerberos is vulnerable is
well-known: the attack goes something like this.

Before a user can use a Kerberised network service, s/he has to log in
to Kerberos. This means the user sends an AS-REQ to the KDC,
containing their principal name and the TGT they are requesting, and the
KDC sends back an AS-REP containing (among other things) the user's TGT
for this session, encrypted with the user's own key. Wait for a user to
log on, and arrange to intercept the AS-REP (Kerberos explicitly assumes
this is possible; it's designed for use on insecure networks).

Now you have a data structure, several parts of which are known or can
be guessed (for instance, the TGT contains the TGT principal in
plaintext), encrypted with the user's key. Guess a password, derive a
key from it, and try the decryption. If you get a valid TGT, you've just
worked out the user's key.

That's not a dictionary attack on the _key_, aka 'someone recovering a
"a secret input" from some scrambled transformation of that' by
running the 'scramble' operation on 'words from some dictionary' and
compare the output created in this step with the other. That's just
ordinary brute-force decryption of something which has been encrypted
with 'knowledge about the plaintext' being used to determine when the
attack was successful.
Repeat until successful. The only limit on how long it takes is the
length of time required to derive the key, which is why slow hashes
with many iterations are important.

Let's assume someone use a single letter password picked from the set
of lowercase and uppercase letters. That would make 52 different
possible passwords and the time required to determine that by brute
force won't sigificantly depend on the speed of the key derivation
algortim for any key derivation algorithm which is still 'fast enough'
that a user cannot possibly throw the computer out of the window and
buy a competing product in the time he has to wait while logging in.

No matter how 'slow' the derivation function is, the main 'time
consuming operation' needs to be 'going through the set of all
possible inputs'.
 
R

Rainer Weikusat

Ben Morrow said:
Wrong. A hash which produces partially-predicatable output given
partially-predicatable input will map the thoroughly-non-uniform space
of passphrases onto a non-uniform subset of the space of possible keys,
effectively reducing the size of the key.

In other words, "f(x) = 1 is not a suitable compression function for
deriving an encryption key from some 'password' string". I agree with
that.
 
R

Rainer Weikusat

Rainer Weikusat said:
[...]
Before a user can use a Kerberised network service, s/he has to log in
to Kerberos. This means the user sends an AS-REQ to the KDC,
containing their principal name and the TGT they are requesting, and the
KDC sends back an AS-REP containing (among other things) the user's TGT
for this session, encrypted with the user's own key. Wait for a user to
log on, and arrange to intercept the AS-REP (Kerberos explicitly assumes
this is possible; it's designed for use on insecure networks).

Now you have a data structure, several parts of which are known or can
be guessed (for instance, the TGT contains the TGT principal in
plaintext), encrypted with the user's key. Guess a password, derive a
key from it, and try the decryption. If you get a valid TGT, you've just
worked out the user's key.

That's not a dictionary attack on the _key_,

After some superficial amount of research, it seems that Ben's more
general use of the term is consistent with 'established practice' (eg,
RFC494) while my more limited interpretation is not.
 
R

Rainer Weikusat

Ben Morrow said:
No, in other words, the compression function must be a cryptographically
strong hash, in the sense that it's impossible to predict any properties
of the output given knowledge of any properties of the input.

As written, this requirement makes no sense: Except if a function
performs a random mapping, predicting the output based on the input is
always possible.
I believe MD5 is no longer considered to be cryptographically
strong.

There's a known algorithm for creating different inputs yielding the
same MD5 hash. This means MD5 is known to be a bad choice for digital
signatures supposed to apply to 'document formats' which allow a
prospective attacker to embed arbitrary 'binary noise' in ways which
will usually not be noticed by a human 'consumer' of the document.
 
R

Rainer Weikusat

Ben Morrow said:
Quoth Rainer Weikusat <[email protected]>:
[...]
Let's assume someone use a single letter password picked from the set
of lowercase and uppercase letters. That would make 52 different
possible passwords and the time required to determine that by brute
force won't sigificantly depend on the speed of the key derivation
algortim for any key derivation algorithm which is still 'fast enough'
that a user cannot possibly throw the computer out of the window and
buy a competing product in the time he has to wait while logging in.

The difference between a computation which, done once, takes a
nanosecond and one which takes a whole second is a billionfold, yet a
user is extremely unlikely to notice an additional delay of a
second.

And the difference between a brute-force attack which needs 52
seconds to recover a password and one which needs 52 nanoseconds is
practically irrelevant except if a 'large' number of passwords are
supposed to be uncovered. And the algorithm may well need only 1s to
recover the password when 52 $somethings can calculate different
possibly correct results in parallell. Of course, two months from now,
hardware or even software(!) capable of performing the '1s'
calculation in a nanosecond will become available ...

That simply isn't possible with human-memorable keys, especially if
users are allowed to choose their own passwords. (And not allowing them
to do so brings a whole other set of security problems, starting with
PostIt notes on monitors.)

"It is not possible. It is possible but humans won't do that. If they
do it, they will trigger "the PostIt" and then, we're all doomed, mark
my words!" ?
 
M

Markus Steinborn

Rainer said:
If you have access to 'a secure channel' which can be used to
communicate two non-random strings which can be turnt into an
encyrption key and initialization vector, why don't you just use a
random key and a random IV and the same 'secure channel' to enable
sender and recipient to share them?

The secure channel is the users memory - quite good for passphrases, but
very very bad for random numbers. And the salt is stored with the
encrypted message.

And for security reasons, I'm developing a perl script for reencryption
(that is decrypting and then encrypting with a new passphrase. That way
I might change the key generation algoririthm witghout pain, but for now
the ciphertexts are encrypted in the same way "openssl enc" would do.

Greetings

Markus
 
M

Markus Steinborn

Charles said:
openssl will handle SHA so perhaps a very small patch to Crypt::CBC and
the script itself to replace Digest::MD5::md5 with Digest::SHA::sha1
might be another option...

Well, I am not using openssl for encryption/decryption. But I found out
by testing that key generation is compatible to openssl with default
values, so asking the question this way seemed the best way to me.

Currently we are using JavaScript for encryption/decryption - and I am
building a perl script that allows changing passphrases by decrypting
and then encrypting the data.

In the middle term whis would allow canging the key generation
algorithm, too. But for now, it is even more important allowing changing
of passphrases.

I'll consider changing the algorithm to use PBKDF2 (with SHA-3 as HMAC?).


Markus
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,019
Latest member
RoxannaSta

Latest Threads

Top