Security review of an authenticated Diffie Hellman variant - networking

EDIT
I'm still hoping for some advice on this, i tried to clarify my intentions...
When i came upon device pairing in my mobile communication framework i studied a lot of papers on this topic and and also got some input from previous questions here. But, i didn't find a ready to implement protocol solution - so i invented a derivate and as i'm no crypto geek i'm not sure about the security caveats of the final solution:
The main questions are
Is SHA256 sufficient as a commit function?
Is the addition of the shared secret as an authentication info in the commit string safe?
What is the overall security of the 1024 bit group DH
I assume at most 2^-24 bit probability of succesful MITM attack (because of 24 bit challenge). Is this plausible?
What may be the most promising attack (besides ripping the device out off my numb, cold hands)
This is the algorithm sketch
For first time pairing, a solution proposed in "Key agreement in peer-to-peer wireless networks" (DH-SC) is implemented. I based it on a commitment derived from:
A fix "UUID" for the communicating entity/role (128 bit, sent at protocol start, before commitment)
The public DH key (192 bit private key, based on the 1024 bit Oakley group)
A 24 bit random challenge
Commit is computed using SHA256
c = sha256( UUID || DH pub || Chall)
Both parties exchange this commitment, open and transfer the plain content of the above values.
Alice Bob
ca = commit()
-------^ ca
cb = commit()
cb ^-----------
open
---^ DH pub a, chall a
open
DH pub b, chall b ^---
The 24 bit random is displayed to the user for manual authentication
DH session key (128 bytes, see above) is computed
When the user opts for persistent pairing, the session key is stored with the remote UUID as a shared secret
Next time devices connect, commit is computed by additionally hashing the previous DH session key before the random challenge. For sure it is not transfered when opening.
c = sha256( UUID || DH pub || DH sess || Chall)
Now the user is not bothered authenticating when the local party can derive the same commitment using his own, stored previous DH session key. After succesful connection the new DH session key becomes the new shared secret.
As this does not exactly fit the protocols i found so far (and as such their security proofs), i'd be very interested to get an opinion from some more crypto enabled guys here. BTW. i did read about the "EKE" protocol, but i'm not sure what the extra security level is.

"Is SHA256 sufficient as a commit function?"
The use of SHA256 should be just fine. The only issue I have heard of is that it has a hash extension vulnerability. If you produce multiple hashes using the same data don't simply concat more data to the end of the data you already hashed. In your post have have the two hashes "sha256( UUID || DH pub || Chall)" and "sha256( UUID || DH pub || DH sess || Chall)". If that second one was "sha256( UUID || DH pub || Chall || DH sess)" then there would be a relation between the hash values if UUID, DH pub, and Chall were all the same values as before. You should either take care to avoid the hash extension issue or include a salt value into the data to be hashed, either by communicating the salt across the link or having differing vales for each code path.
On a side note: is it really necessary to transmit a Chall when you already have a previous session key saved and don't need to ask the user to manually confirm the challenge code?
"Is the addition of the shared secret as an authentication info in the commit string safe?"
I'm guessing you mean to ask "Is it safe to include secret information in a hash that is to be made public?" If the secret is something that is really hard to guess and would take a really long time to perform a bruteforce attack against, then yes it is safe. If the secret is something easy to guess or has only a few possible values, then no, it's not safe unless you, at the same time, include some hard to guess secret to force a potential eavesdropper to have to guess all such secrets simultaneously. For a large, effectively random number like a DH shared secret then it should be just fine.
"What is the overall security of the 1024 bit group DH"
I'm not sure if DH group 1024 is what you want to use. A key exchange that is considered to be close to being as effective as the SHA256 hash algorithm you're using would be 521 bit ECDH. The cryptographic strength of ECDH is considered to be 1/2, so if you want 256 bit security, you want 521 bit ECDH. Unfortunately, I'm not certain about the security of the many individual 521 bit ECDH groups that have been published.
"I assume at most 2^-24 bit probability of succesful MITM attack (because of 24 bit challenge). Is this plausible?"
There is more than one way perform a MITM attack. Eve will use every resource at her disposal to perform her attacks and if you are not careful she will exploit something you didn't think of. This is why peer review is necessary in cryptography.

Simply, if you make your own cryptographic solution, then it's weak.
for the little story, the VISA guys have to start again 4 times before it's became strong enough.
I'm not a security expert, but it was what my crypto teacher told us everytime.

I've come up with this possible attack, based on my understanding of the protocol, inspired by Lowe's Attack to Needham-Shroeder Public Key Protocol:
Alice wants to reconnect. Calculates its committment ca and sends to Bob. The message is captured by Mallory.
Mallory answers. She does not know the shared secret, so she invents one. Calculates cb and sends to Alice.
At this step, Alice cannot verify the shared secret yet. So she sends DHpubA and ChallA.
Mallory ignores the messages from Alice and disappears.
Now Mallory has a valid DHpubA, ChallA and the corresponding (valid) ca.
Mallory sends ca to Bob.
Bob answers with cb.
Mallory sends a valid set of DhpubA, ChallA
Bob sends his DhpubB and ChallB
Since Bob can validate Mallory's messages, she is authenticated as Alice. Obviously Mallory does not know DHprivA, se she cannot calculate the current session key, but nevertheless you have a security flaw since Bob thinks he's talking to Alice.
General advice: avoid implementing you own cryptographic solution and don't trust security reviews from anyone else than an established security firm.
If you feel that your security requirements are not satisfied by standard mainstream crypto, try stating your requirements and asking whether is there a security procotol that matches them.

That sounds OK. Not sure what you meant by "fix[ed] UUID"?
Could a rogue app access the UUID and session keys: are they stored system-wide or in a service? There is some text in the SDK that suggests that any keystore always waits for user confirmation before returning a key.

Related

Why encrypt message digest in digital signature?

I am trying to understand the following:
Why should a message digest in cryptography be encrypted with the private key from the sender?
The receiver can decrypt it with the public key of the sender, but anyone else can do that too. Even the man in the middle, so I don't really see the point of encrypting the message digest in the sense of Digital Signature.
Try to separate encryption and signing. Even mathematically they are similar operations, there are some important differences. I will try to summarize basics
mesaage and uses his own private key to encrypt the message digest
Actually - person A creates a hash of the content and signs the hash. It means executing a decryption operation with signing padding with its private key, creating a signature
Now person B will make a hash value of the message to compare it to the message digest.
And this is wrong. Whoever (any attacker) could modify/falsify the content and create a valid digest.
Person B
creates a hash value of the content
validates the provided signature - encrypts the provided signature with A's public key which should result to the hash and signing padding
but anyone else can do that too
Signing ensures, that only A could sign the mesage digest, because only with private key you could "decrypt" - create an output, which after "encryption" could lead to some specific value (digest).
It is as well important to use full specification for RSA operations (PSS padding), not text-book RSA (without nonce and padding). Otherwise if some could trick A to decrypt any input, leading to creating a signature or revealing the private key.
Edit:
why isnt it enoug to encrypt with pulic key
Encrypting ensures, that only the addressee could decrypt the message, but it doesn't say who is sending the message. (A can believe that only B reads the message, but B may not be sure it is a message from A)
Signing undeniably identifies the sender. (B can be sure the message is sent by A)
There are some caveats in this approach (signing a directly encrypted message), but details could be better explained in the crypto OS forum.

How do I encrypt an email using a Yubikey?

I am fairly new to PGP encryption. I generated a new key pair last week on a Yubikey, while previously I had only used a private key that I generated on my machine. I use thunderbird enigmail for key management. This is probably a stupid question but I don't actually understand how to encrypt an email using the private key stored on my Yubikey. I can decrypt just fine but can't figure out how to compose an encrypted email from the new key. Using my old key pair, it's automatic - how do I actually encrypt using the right private key? At what point do I enter the Yubikey and pin? (I'm not all that technical and I use encryption for one specific project, so I appreciate dumbing down something that is probably very obvious.)
Using keys generated on a Yubikey is a practically identical process to using your old keys, with one extra step of set up.
To use keys stored on a Yubikey, you need "key stubs" registered on your PGP system. Basically, these are references that tell your PGP software "This private key is located on smartcard number #123456." Once you have the stubs to the keys you need, Enigmail should treat the Yubikey-stored keys like any other PGP key.
I'm only familiar with GnuPG, so specifics may vary, but using GPG you need to
Have a copy of the public key imported to your system from a key server or the like.
Import key stubs from your smart card (in this case, your Yubikey) using:
gpg --card-status
After that, checking your private keyring should reflect that you have stubs pointing to private keys stored on a smart card (denoted by the > after sub). I.E.
gpg --list-secret-keys
----------------------------------------------------
sec# rsa2048 2018-01-02 [C] [expires: 2020-01-02]
ABCDEF123456789ABCDEF123456789ABCDEF1234
uid [ ultimate] My Name (My PGP key) <anAddress#somesite.com>
ssb> rsa2048 2018-01-02 [S] [expires: 2018-12-31]
ssb> rsa2048 2018-01-02 [E] [expires: 2018-12-31]
ssb> rsa2048 2018-01-02 [A] [expires: 2018-12-31]
At this point you can use sub keys of CDEF1234 as if there were on your system. Your PGP software ought to handle checking the card is inserted and dealing with PIN entry.

AES-256 best practices implementation

I'm reversing an app but I'm not very expert of the AES algorithm.
The application gives the user the opportunity to make an offline login.
The user is asked to provide his username and password
This is the function that is used to store the info of the user
public void EncryptLoginInfo(string username, byte[] secretShared, byte[] salt)
{
byte[] random = calc.GenerateRandomBytes();
byte[] array = aes.Encrypt(secretShared, random);
OfflineLogin loginInfo = new OfflineLogin()
{
Username = username,
SecretShared = array,
Iv = random,
Salt = salt
};
this._userCredentials.StoreOfflineLoginData(username, loginInfo);
}
And this are the info that are stored inside an internal config file of the app. In the example below, the password passed to the encryptLoginInfo is 123
Username: not_important
SecretShared: 4KVrjy1cQVWYpWF7aolpMS0HzhKyFf+9VXauQrXoXVUbf0bGXIDOLDJuSVhYoFo2
Iv:yil4nn02IoKsOnX5KXVsDg==
Salt: 5kJio2VQEqjomHRdQMqRVJ0zkBsmqi8K3NypC2VWJk4
If the user want to make an offline login, he is asked to provide username and his password.
Question: Is this algo safe? If an attacker is able to obtain SecretShared+Iv+Salt is he able to recover the password of the user (that in this specific example is 123)
This is the decrypt function
public void DencryptLoginInfo(OfflineLogin loginInfo)
{
byte[] array = aes.Decrypt(loginInfo.SecretShared, loginInfo.Iv);
loginInfo.SecretShared = array;
loginInfo.Iv = (byte[]) null;
}
Are you able to spot any security issues in this implementation? The algo used should be AES-256.. Are you able to implement a POC in python to decrypt the PASSWORD given SecretShared+Iv+Salt?
According to your comment, your goal is to authenticate the user. For that we use password base key derivation functions on the password. Often people refer to this as "hashing passwords", which is unfortunate terminology because "hashing" can mean anything. But the main point is that we do not encrypt passwords, instead we send them through a one-way function that is designed to be slow. The slow speed deters brute force attacks.
You do not need an IV to do this. Instead, your app should be deriving a salt and and using a password based key derivation function (sometimes referred to as a "password hashing" algorithm: you will have to excuse that the industry has made a mess out of the terminology on this topic). You can find guidance on this all over the web. But I suggest you have a read of point 4 in Top 10 Developer Crypto Mistakes to see common pitfalls in implementing this.
Don't use openssl to convert a password into a key (or password hash)! The algorithm in openssl is weak. Openssl's EVP_BytesToKey() fails to meet the requirements of slow speed, meaning that it is easy to brute force your key from your password.
The proper solution to this problem is to use an algorithm such as bcrypt or pbkdf2 (Java implementations can be found without much effort) to derive a "hash" from the password. You then verify that the user typed in the password correctly by re-doing the same computation with the user entered password and the salt that was stored for this password. If they match, access is granted, otherwise access is denied.
Note that if this app interacts with a server, normally you do password verification on the server side. If your app does not interact with a server, then you may have a good reason to do it on the device. I don't know what your app does, so I cannot tell you what is right or wrong for you.
A great reference for doing this properly is How to Safely Store Your Users' Passwords in 2016 .

LUKS change encryption key

I found on this forum some very interesting content for problem that I have, but I don't found answer for my question.
To change encryption password I can use command:
cryptsetup luksChangeKey /dev/sda2
... and that works. But how to encrypt /dev/sda2 partition again with new password?
If my old password is compromised and I only change password, stored data is encrypted with old password not with new.
The LUKS partition itself is not encrypted with your password: it is encrypted with a strong "master key" randomly calculated upon volume creation. Your old and new passwords only serve to encrypt the "master key". Unfortunately both passwords and the "master key" as often referred to as "keys" hence your (and others') confusion.
When in the old days cryptsetup did not rely on LUKS, every time you changed your cryptsetup password the entire disk would have to be re-encrypted!
Nowdays you only have to change your master key if someone also gains physical or administrative access to the encrypted device while the password is valid.
p.s. if not relying on temporary storage but having free space, the LUKS master key may be "changed" by shrinking a LUKS volume via "cryptsetup resize", creating another volume, moving data, deleting the first volume and expanding the second volume.

encryption/decryption with multiple keys

Is it possible to encrypt data, such that it can be decrypted with several different keys?
Example:
I've encrypted data with key1, but I want to be able to decrypt with keys 2, 3, and 4.
Is this possible?
GnuPG does multi-key encryption in standard.
The following command will encrypt doc.txt using the public key for Alice and the public key for Bob. Alice can decrypt using her private key. Bob can also decrypt using his private key.
gpg --encrypt --recipient alice#example.com \
--recipient bob#example.com doc.txt
This feature is detailed in the user guide section entitled "Encrypting and decrypting documents"
Yes it's possible
Yes encryption for multiple recipients is possible. Also it seems logical when you think that you might want to be able to read what you've sent to someone and to do so you need to be in the recipients list.
Command line
Here is how to do it through gpg command line (as described in David Segonds' answer):
gpg --encrypt \
--recipient alice#example.com \
--recipient bob#example.com \
clear-message.txt
GUI client
Your GUI must provide a way to encrypt for several people
Mechanism
There is a question on Information Security, GPG File size with multiple recipients?, that explain the encryption mechanism:
GPG encrypts the file once with a symmetric key, then places a header
identifying the target keypair and an encrypted version of the
symmetric key.
[...] When encrypted to multiple recipients, this
header is placed multiple times providing a uniquely encrypted version
of the same symmetric key for each recipient.
GnuPG and PGP clients in general usually encrypt the actual data with a symmetric key called a "session key". The session key is then encrypted with each "recipient key" (i.e. the ones you specify with -r/--recipient). This is sometimes referred to as a hybrid cipher. Right now, I believe GnuPG by default uses an 256 bit session keys and AES to encrypt the plaintext data to that AES-256 session key, and your recipient keys are your RSA/DSA/ECDSA/etc. assymetric key in this case.
One reason for doing it this way is that symmetric cryptographic algorithms like AES are generally a lot faster than asymmetric ones like RSA. GnuPG thus only has to encrypt ~256 bits (the session key) with RSA, and can use AES to encrypt the data (as large as you want it to be!) with that session key. Intel machines even have a built in instruction, AES-NI, to do some steps of the algorithm in hardware, which makes GnuPG extra snappy at encrypting/decrypting data.
Another reason for doing it this way is that it allows PGP-encrypted documents to be encrypted to multiple parties without having to double the size of the document. Notice that when you specify multiple recipients for an encrypted document (e.g. gpg -ea -r Alice -r Bob -o ciphertext.asc), the encrypted document that gets stored (ciphertext.asc) is not 2x as large as if you had just encrypted it to Alice.
See also the --show-session-key parameter in the gpg man page to be able to decrypt just the session key, for example to allow a third party to decrypt a document that is encrypted to you without having to transfer to them your private key or the plaintext data.
Yes, it's possible. Google "multiparty encryption" for a start.
AFAIK, there are no drop 'em in and use 'em packages for it though.
-- MarkusQ
P.S. For a sketch of how it could be done, consider this. The encrypted message consists of:
the payload, encrypted with a one-time pad
the one time pad, encrypted with key1
the one time pad, encrypted with key2
...
the one time pad, encrypted with keyN
The recipient who hold key i just decrypts their copy of the pad with their key, and then decrypts the payload.
However, this is just a proof that it could be done and would suck as an actual implementation. If at all possible, you should avoid rolling your own encryption. If you don't understand why, you should definitely avoid rolling your own encryption.
-----Edit ------------
If I'm wrong and the Gnu tools do that, use them. But I can't seem to find any information on how to do it.
Multiple (more than two) key RSA is maybe like this - well i'm not a mathematician, so this algorithm is not necessarily secure, i just want to give an idea with it.
m=p*q*r; p,q,r are big prime numbers
fi(m)=(p-1)(q-1)(r-1)
d==(e1*e2*e3*...*ei)^(-1) (mod fi(m)); e1...ei are arbitrary numbers, d is calculated to fulfill the equation
y1==x^e1 (mod m)
y2==y1^e2 (mod m)
y3==y2^e3 (mod m)
...
x==yi^d (mod m)
This algorithm could be used for example to increase the speed of The Onion Router.

Resources