Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shared key for symetric encryption #3

Open
olivierch opened this issue Sep 27, 2013 · 8 comments
Open

shared key for symetric encryption #3

olivierch opened this issue Sep 27, 2013 · 8 comments

Comments

@olivierch
Copy link

I did not see how could be obtained a large key that was known at the end of exchanges and known only by both sides. We cannot perform symmetric encryption without it. Could you explain that?

@cocagne
Copy link
Owner

cocagne commented Sep 27, 2013

It's inherent to the math underlying the SRP algorithm. If you haven't
already, I suggest you take a look at the end of the pysrp documentation.
There's a description of the algorithm there that will hopefully shed some
light on the issue. Ultimately and at the end of the exchange, both
endpoints are left with a unique value that is known only to them and that
may be used for symmetric encryption. I'm not really sure how to explain
further. Is you question based more on and understanding of the mathematics
or a understanding of the implementation?

On Fri, Sep 27, 2013 at 12:33 AM, Olivier Chaussavoine <
[email protected]> wrote:

I did not see how could be obtained a large key that was known at the end
of exchanges and known only by both sides. We cannot perform symmetric
encryption without it. Could you explain that?


Reply to this email directly or view it on GitHubhttps://github.com//issues/3
.

@olivierch
Copy link
Author

You are right, I found the method get_session_key() that solved the problem. I was wondering which kind of symmetric cipher could be used when this key is set, I chose Crypto.Cipher.AES and initialized it like this:

from Crypto.Cipher import AES
from Crypto.Hash import SHA256

def getAES(pwd,iv):
    _hash = SHA256.new()
    _hash.update(pwd)
    return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])

where iv is returned by the method get_session_key(). The password is hashed in order to obtain a key with 32 bytes. I just use the methods encrypt() and decrypt() of the object returned by getAES(pwd,iv).

Have you an opinion on this implementation?

@cocagne
Copy link
Owner

cocagne commented Oct 1, 2013

AES is a good choice for the encryption algorithm. It's pretty standard and
has a good security rating. You should use the SRP session key as the AES
key and the IV should, ideally, be random data. The IV isn't secret
information and you can send it across the network to the receiver so they
can use the same value.

A word of caution here though. The likelihood that you'll make a mistake
with your use of encryption is close to 100%. It's extremely difficult to
achieve good security even for cryptography experts. If your use-case
really does require tight security, I'd suggest that you first try and
closely follow the encryption approach used by some other protocol. You
could, for example, use an encryption model that closely follows TLS packet
encryption. Second and after you've done the first, try and find someone
with a good crypto background to vet your implementation.

Good luck.

Tom

On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine <
[email protected]> wrote:

You are right, I found the method get_session_key() that solved the
problem. I was wondering which kind of symmetric cipher could be used when
this key is set, I chose Crypto.Cipher.AES and initialized it like this:

from Crypto.Cipher import AESfrom Crypto.Hash import SHA256
def getAES(pwd,iv):
_hash = SHA256.new()
_hash.update(pwd)
return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])

where iv is returned by the method get_session_key(). The password is
hashed in order to obtain a key with 32 bytes. I just use the methods
encrypt() and decrypt() of the object returned by getAES(pwd,iv).

Have you an opinion on this implementation?


Reply to this email directly or view it on GitHubhttps://github.com//issues/3#issuecomment-25230442
.

@olivierch
Copy link
Author

I beleived the result obtained by get_session_key() was random and only
known by both sides. Am I wrong?

Your second argument is very wise and respectfull, but I do very simple
things with that:

  1. srp challenge giving me a session key,
  2. symetric encryption with AES using this session key.

2013/10/1 cocagne [email protected]

AES is a good choice for the encryption algorithm. It's pretty standard
and
has a good security rating. You should use the SRP session key as the AES
key and the IV should, ideally, be random data. The IV isn't secret
information and you can send it across the network to the receiver so they
can use the same value.

A word of caution here though. The likelihood that you'll make a mistake
with your use of encryption is close to 100%. It's extremely difficult to
achieve good security even for cryptography experts. If your use-case
really does require tight security, I'd suggest that you first try and
closely follow the encryption approach used by some other protocol. You
could, for example, use an encryption model that closely follows TLS
packet
encryption. Second and after you've done the first, try and find someone
with a good crypto background to vet your implementation.

Good luck.

Tom

On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine <
[email protected]> wrote:

You are right, I found the method get_session_key() that solved the
problem. I was wondering which kind of symmetric cipher could be used
when
this key is set, I chose Crypto.Cipher.AES and initialized it like this:

from Crypto.Cipher import AESfrom Crypto.Hash import SHA256
def getAES(pwd,iv):
_hash = SHA256.new()
_hash.update(pwd)
return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])

where iv is returned by the method get_session_key(). The password is
hashed in order to obtain a key with 32 bytes. I just use the methods
encrypt() and decrypt() of the object returned by getAES(pwd,iv).

Have you an opinion on this implementation?


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25230442>
.


Reply to this email directly or view it on GitHubhttps://github.com//issues/3#issuecomment-25422744
.

Olivier Chaussavoine

@cocagne
Copy link
Owner

cocagne commented Oct 2, 2013

Oh, ok. I think I follow you now. You're intentionally using a derivative
of the user's password as the AES encryption key and using the SRP session
key to avoid having to explicitly send the IV over the network. It sounds
reasonable and I can't think of anything specifically wrong with that
approach but I would have a few concerns about taking this approach for one
of my projects. Specifically:

  • This approach requires either storing the raw user's password in the
    server's database or both the SRP verifier and the SHA256 hash of the
    password. Were you to use the session key as the AES key, only the SRP
    verifier would be required.
  • It is significantly easier to recover the user's password from a
    compromised SHA256 hash of the user's password than it is to recover it
    from the SRP verifier (which is salted)
  • It goes against the common practice of using the SRP session key as the
    symmetric encryption key.

The last point there is a little fuzzy but crypto is so easy to get wrong
it's almost always a good idea to follow the common practice unless you
have a compelling reason to do otherwise. That said though, your approach
might be fine. It looks like it should be but I'm far from a security
expert.

Tom

On Tue, Oct 1, 2013 at 11:53 AM, Olivier Chaussavoine <
[email protected]> wrote:

I beleived the result obtained by get_session_key() was random and only
known by both sides. Am I wrong?

Your second argument is very wise and respectfull, but I do very simple
things with that:

  1. srp challenge giving me a session key,
  2. symetric encryption with AES using this session key.

2013/10/1 cocagne [email protected]

AES is a good choice for the encryption algorithm. It's pretty standard
and
has a good security rating. You should use the SRP session key as the
AES
key and the IV should, ideally, be random data. The IV isn't secret
information and you can send it across the network to the receiver so
they
can use the same value.

A word of caution here though. The likelihood that you'll make a mistake
with your use of encryption is close to 100%. It's extremely difficult
to
achieve good security even for cryptography experts. If your use-case
really does require tight security, I'd suggest that you first try and
closely follow the encryption approach used by some other protocol. You
could, for example, use an encryption model that closely follows TLS
packet
encryption. Second and after you've done the first, try and find someone
with a good crypto background to vet your implementation.

Good luck.

Tom

On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine <
[email protected]> wrote:

You are right, I found the method get_session_key() that solved the
problem. I was wondering which kind of symmetric cipher could be used
when
this key is set, I chose Crypto.Cipher.AES and initialized it like
this:

from Crypto.Cipher import AESfrom Crypto.Hash import SHA256
def getAES(pwd,iv):
_hash = SHA256.new()
_hash.update(pwd)
return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])

where iv is returned by the method get_session_key(). The password is
hashed in order to obtain a key with 32 bytes. I just use the methods
encrypt() and decrypt() of the object returned by getAES(pwd,iv).

Have you an opinion on this implementation?


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25230442>
.


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25422744>
.

Olivier Chaussavoine


Reply to this email directly or view it on GitHubhttps://github.com//issues/3#issuecomment-25467976
.

@olivierch
Copy link
Author

You got it! You let me think it could be possible to avoid storing a clear
password in the server database. That was not my requirement. Do we just
need to compute the verifier and store it with uname in the database for
all future sessions, or each time a new session is initiated? I chose the
second solution storing only uname and password in the database.
I am not a security expert either, and more afraid by taking the risk of
sending a clear IV on the network than storing clear passwords on my
database.

Olivier

2013/10/2 cocagne [email protected]

Oh, ok. I think I follow you now. You're intentionally using a derivative
of the user's password as the AES encryption key and using the SRP session
key to avoid having to explicitly send the IV over the network. It sounds
reasonable and I can't think of anything specifically wrong with that
approach but I would have a few concerns about taking this approach for
one
of my projects. Specifically:

  • This approach requires either storing the raw user's password in the
    server's database or both the SRP verifier and the SHA256 hash of the
    password. Were you to use the session key as the AES key, only the SRP
    verifier would be required.
  • It is significantly easier to recover the user's password from a
    compromised SHA256 hash of the user's password than it is to recover it
    from the SRP verifier (which is salted)
  • It goes against the common practice of using the SRP session key as the
    symmetric encryption key.

The last point there is a little fuzzy but crypto is so easy to get wrong
it's almost always a good idea to follow the common practice unless you
have a compelling reason to do otherwise. That said though, your approach
might be fine. It looks like it should be but I'm far from a security
expert.

Tom

On Tue, Oct 1, 2013 at 11:53 AM, Olivier Chaussavoine <
[email protected]> wrote:

I beleived the result obtained by get_session_key() was random and only
known by both sides. Am I wrong?

Your second argument is very wise and respectfull, but I do very simple
things with that:

  1. srp challenge giving me a session key,
  2. symetric encryption with AES using this session key.

2013/10/1 cocagne [email protected]

AES is a good choice for the encryption algorithm. It's pretty
standard
and
has a good security rating. You should use the SRP session key as the
AES
key and the IV should, ideally, be random data. The IV isn't secret
information and you can send it across the network to the receiver so
they
can use the same value.

A word of caution here though. The likelihood that you'll make a
mistake
with your use of encryption is close to 100%. It's extremely difficult
to
achieve good security even for cryptography experts. If your use-case
really does require tight security, I'd suggest that you first try and
closely follow the encryption approach used by some other protocol.
You
could, for example, use an encryption model that closely follows TLS
packet
encryption. Second and after you've done the first, try and find
someone
with a good crypto background to vet your implementation.

Good luck.

Tom

On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine <
[email protected]> wrote:

You are right, I found the method get_session_key() that solved the
problem. I was wondering which kind of symmetric cipher could be
used
when
this key is set, I chose Crypto.Cipher.AES and initialized it like
this:

from Crypto.Cipher import AESfrom Crypto.Hash import SHA256
def getAES(pwd,iv):
_hash = SHA256.new()
_hash.update(pwd)
return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])

where iv is returned by the method get_session_key(). The password
is
hashed in order to obtain a key with 32 bytes. I just use the
methods
encrypt() and decrypt() of the object returned by getAES(pwd,iv).

Have you an opinion on this implementation?


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25230442>
.


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25422744>
.

Olivier Chaussavoine


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25467976>
.


Reply to this email directly or view it on GitHubhttps://github.com//issues/3#issuecomment-25510951
.

Olivier Chaussavoine

@cocagne
Copy link
Owner

cocagne commented Oct 2, 2013

You only need to calculate the verifier once and it may be used for all
future SRP authentication attempts. As for the IV, it's not a secret value
so you can send it over the network in the clear and without concern. In
fact, when AES encryption is being used in DTLS (the UDP version of SSL),
each packet has a random IV prepended to the encrypted data block. All you
need to do is make sure the IV comes from a good source of random data. On
Linux systems, you can just read the appropriate number of bytes from
/dev/urandom. There's a section on Initialization Vectors used in block
ciphers on Wikipedia that might help:
http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Initialization_vector_.28IV.29

As for storing the passwords directly in the database, please try to
avoid this if at all possible. It seems innocuous but remember that people
tend to reuse passwords even when you tell them not to. If your database is
somehow hacked, it could lead to bigger, seemingly unrelated problems when
the attackers test those username,password combinations on other sites.
Financial websites aside, even just gaining access to someone's web e-mail
account could give an attacker enough personal information for identity
theft.

Cheers,

Tom

On Wed, Oct 2, 2013 at 1:25 AM, Olivier Chaussavoine <
[email protected]> wrote:

You got it! You let me think it could be possible to avoid storing a clear
password in the server database. That was not my requirement. Do we just
need to compute the verifier and store it with uname in the database for
all future sessions, or each time a new session is initiated? I chose the
second solution storing only uname and password in the database.
I am not a security expert either, and more afraid by taking the risk of
sending a clear IV on the network than storing clear passwords on my
database.

Olivier

2013/10/2 cocagne [email protected]

Oh, ok. I think I follow you now. You're intentionally using a
derivative
of the user's password as the AES encryption key and using the SRP
session
key to avoid having to explicitly send the IV over the network. It
sounds
reasonable and I can't think of anything specifically wrong with that
approach but I would have a few concerns about taking this approach for
one
of my projects. Specifically:

  • This approach requires either storing the raw user's password in the
    server's database or both the SRP verifier and the SHA256 hash of the
    password. Were you to use the session key as the AES key, only the SRP
    verifier would be required.
  • It is significantly easier to recover the user's password from a
    compromised SHA256 hash of the user's password than it is to recover it
    from the SRP verifier (which is salted)
  • It goes against the common practice of using the SRP session key as
    the
    symmetric encryption key.

The last point there is a little fuzzy but crypto is so easy to get
wrong
it's almost always a good idea to follow the common practice unless you
have a compelling reason to do otherwise. That said though, your
approach
might be fine. It looks like it should be but I'm far from a security
expert.

Tom

On Tue, Oct 1, 2013 at 11:53 AM, Olivier Chaussavoine <
[email protected]> wrote:

I beleived the result obtained by get_session_key() was random and
only
known by both sides. Am I wrong?

Your second argument is very wise and respectfull, but I do very
simple
things with that:

  1. srp challenge giving me a session key,
  2. symetric encryption with AES using this session key.

2013/10/1 cocagne [email protected]

AES is a good choice for the encryption algorithm. It's pretty
standard
and
has a good security rating. You should use the SRP session key as
the
AES
key and the IV should, ideally, be random data. The IV isn't secret
information and you can send it across the network to the receiver
so
they
can use the same value.

A word of caution here though. The likelihood that you'll make a
mistake
with your use of encryption is close to 100%. It's extremely
difficult
to
achieve good security even for cryptography experts. If your
use-case
really does require tight security, I'd suggest that you first try
and
closely follow the encryption approach used by some other protocol.
You
could, for example, use an encryption model that closely follows TLS
packet
encryption. Second and after you've done the first, try and find
someone
with a good crypto background to vet your implementation.

Good luck.

Tom

On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine <
[email protected]> wrote:

You are right, I found the method get_session_key() that solved
the
problem. I was wondering which kind of symmetric cipher could be
used
when
this key is set, I chose Crypto.Cipher.AES and initialized it like
this:

from Crypto.Cipher import AESfrom Crypto.Hash import SHA256
def getAES(pwd,iv):
_hash = SHA256.new()
_hash.update(pwd)
return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])

where iv is returned by the method get_session_key(). The password
is
hashed in order to obtain a key with 32 bytes. I just use the
methods
encrypt() and decrypt() of the object returned by getAES(pwd,iv).

Have you an opinion on this implementation?


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25230442>
.


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25422744>
.

Olivier Chaussavoine


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25467976>
.


Reply to this email directly or view it on GitHub<
https://github.com/cocagne/pysrp/issues/3#issuecomment-25510951>
.

Olivier Chaussavoine


Reply to this email directly or view it on GitHubhttps://github.com//issues/3#issuecomment-25515678
.

@simbo1905
Copy link

To be clear to anyone reading this the correct approach is to:

  1. Register the users SRP salt and SRP verifier over TSL/SSL to protect the verifier against being intercepted for an offline brute force attack. Also you want to protect the user id which if known can allow for online guessing attacks trying 'obvious' passwords: so use TSL/SSL for both the registration and the login for extra protection.
  2. For bonus marks use a client side password meter widget to show the user if their password is strong to encourage them to use a string password which cannot be guessed quickly with such an 'obvious password' slow online attack.
  3. For follow on cryptography with AES use the SRP shared session key (which should be a hash of the SRP 'S' value) as the AES key. That's the shared secret. AES also needs a fresh none secret random value every usage of the shared key. In layman's terms (I am not a cryptographer) internally to AES it does the equivalent of salting the key with the per-usage random to get a unique pre-usage key. That prevents the user uploading lots of similar data which have common bit patterns which leak info about the shared secret key. In WWII they jammed enemy comms to force them to retransmit using the same key just to use this attack to crack their codes. So every use of a shared key needs a unique random publicly shared value to protect the shared secret key additional with randomness.

End.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants