Problem
I want to sign and encrypt (effectively, obfuscate) some information ('token') on my server (a trusted environment) and send the cyphertext to a client machine (not quite trusted environment) to be read and verified by my client-side software. This type of the environment allows me to have a private key on the server for asymmetric signing, but I cannot 'hide' a secret key for symmetric signing on a client side.
Alternatives
I chose to use JWT as a standard and Nimbus JOSE+JWT library as an implementation for signing and encryption. Nimbus library provides two options for sign + encrypt: nest JWS into JWE or use JWE with authenticated encryption algorithm (A128CBC_HS256, A192CBC_HS384, or A256CBC_HS512). Algorithm Selection Guide for Nimbus states:
Encryption in JOSE is always authenticated, meaning that ciphertext’s integrity is protected from tampering. Authenticated encryption thus makes nesting an HMAC JWT inside a JSON Web Encryption (JWE) redundant; use just JWE encryption.
However, AxxxCBC_HSxxx encryption methods use only symmetric keys. Additionally, replacing direct JWE algorithm with RSA JWE algorithm should not help, because an abuser can generate CEK (consisting of encryption key and key for HMAC) themselves and encrypt it with a public key.
Question
Despite the quote about the redundancy of nested JWTs, I concluded, that for my case JWE+JWS nesting is the only workable approach. Am I right?
Clarifications
Every content encryption algorithms (AxxxGCM and AxxxCBC_HSxxx) use a symmetric key (CEK). This key is determined by the key encryption algorithm and its key management mode (random CEK, key agreement, direct key...).
You are right, contrary to the AxxxGCM algorithms, the AxxxCBC algorithms are not authenticated encryption algorithms.
However, the RFC7516 section 5.1 item 15. (specification for JWE) introduces a tag that allows to authenticate the cyphertext and protect the integrity of the protected header (that is why the AxxxCBC algorithm is used with the HSxxx).
This is confirmed by the table in the RFC7518 section 5.1. Details are given in the next section.
In any case, you will need 2 algorithms for JWE computation:
The key encryption algorithm: you mentioned you have an asymmetric key so I guess you will chose an RSA or an ECDH-ES algorithm depending on your key type.
The content encryption key: AxxxGCM or AxxxCBC_HSxxx algorithms. With the JWE specification both offer an authenticated encryption. Personally I prefer AxxxGCM algorithms because they are faster in my environment.
Answer
You indicated that you want sign and encrypt but you cannot hide a secret key on client side thus the signature will not be guaranteed.
If you only encrypt (JWE only), your server will not be able to verify the issuer of the token.
Related
I understand that WebauthN is designed to perform authentication, but I'd like to use my Yubikey to create symmetric encryption keys to encrypt content on my web browser without relying on a backend server.
Here's my approach:
During the assertion challange ( navigator.credentials.get({ publicKey }) ) the Yubikey signs a challenge string that the client sends to the authenticator.
I extract the signed challenge, hash it with SHA256 and use it as my new symmetric encryption key for AES256 encryption.
As long as the same challenge string is sent to the Yubikey, the encryption key will always be the same.
In order to be able to decrypt the content on the web browser. I would have to be in possession of the Yubikey and the challenge string for 2 factor authentication.
Is there anything wrong with this approach?
Why don't you use the Web Crypto API?
This API is designed for cypher operations on client side and is suitable for your use case (client side encryption). It is supported by all recent browsers.
Note that the main concern you may have is that this API does not supports hardware devices (smartcards, security tokens...).
However, your Yubikey is certainly capable of generating a secured static password you can use as a master key you will derive to encrypt/decrypt your data.
Perhaps you could leverage the hmac-secret extension (https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#sctn-hmac-secret-extension)?
No. This is a bad idea for these reasons:
RS256/ES256 are not deterministic signatures. So you will get a new, random signature every time.
Even if you could, there are things like XSS, and this would be broken swiftly.
Use crypto API as mentioned above.
HMAC-Secret is reserved for Platforms at the moment. You can not access it via WebAuthn API.
In the future, there is a large blobs functionality, and largeBlobsKey... But this is a very long future...
You could (mis)use the user.id parameter of the public key request payload, i.e., the user object in the example here: Web Authentication API (example) like this:
Use Web Crypto API to generate a symmetric key
then use that key as user.id in navigator.credentials.create({ user: {id: YOUR_KEY } }) to store the key in the authenticator
store the returned key id/rawId somewhere in your application
To retrieve the key you can use navigator.credentials.get({ publicKey }) by supplying the rawId
I have messages I need to be able to encrypt when being sent. They should only be able to be decrypted by the receiver.
Initially, I had a structure where the message is encrypted using the receiver's public key, and the receiver then uses their private key to decrypt their messages. However, since I was using RSA, the size of the message was quite limited.
I'm imagining two potential solutions, but am not quite sure how to implement the better one (option 2).
(Easy) just split up each message into many smaller parts, encrypt and store those. This would only change the query structure of my app but not the encryption structure.
I could encrypt the messages with symmetric keys, which is faster and works on any size. However, I would then need to encrypt that symmetric key with an asymmetric one. The problem then becomes that I can only decrypt the symmetric key when the asymmetric private one is provided, ie when the receiver wants to read their messages. So in that case, how would I actually encrypt the messages? Since I don't want the sender to be able to access a key used for decryption as well.
The problem then becomes that I can only decrypt the symmetric key when the asymmetric private one is provided, ie when the receiver wants to read their messages. So in that case, how would I actually encrypt the messages?
That's simple, you use an ephemeral, message specific, fully random symmetric key for data encryption before you encrypt it with the public key. Preferably you should explicitly destroy the symmetric key after that. You can prefix the wrapped (encrypted) symmetric key before the ciphertext of the message, as it will always have the same size in bytes as the modulus (i.e. the RSA key size in bytes).
The system you are thinking about, which is much better than splitting up messages for RSA, is called a hybrid cryptosystem. There are various other ways to accomplish the same thing such as RSA-KEM and - for elliptic curves - ECIES. Both are not often present in crypto-libraries though.
If you decide to use RSA/AES for sending cryptograms then I would advice you to use OAEP and e.g. AES-CTR rather than AES-CBC as RSA PKCS#1 v1.5 padding and CBC padding are both vulnerable to padding oracle attacks.
It is highly recommended to sign the messages, otherwise an adversary can encrypt fake messages. Encryption is only used to achieve message confidentiality, not message integrity & authenticity. An adversary may even try plaintext oracle attacks if any message can be send. If you are not allowing a set of private keys that you control then you should sign-then-encrypt, not encrypt-then-sign.
And as always, prefer TLS or other explicit secure transport protocols if that's an option for transport security.
Is there practical difference between HS256 and HS512 encryption algorithms, or is the additional security from longer key redundant compared to already unbreakable key? Which one should I use to encrypt the JWT token?
Is it even possible to use HS512 encryption with auth0's java JWT?
The algorithm is used to perform a digital signature (not encryption) over the header and payload of the token. If you want to encrypt the token payload, you need to apply the JWE standard (see RFC)
Is there a practical difference between HS256 and HS512 encryption algorithms, or is the additional security from longer key redundant compared to already unbreakable key? Which one should I use to encrypt the JWT token?
HS256 means HMAC-SHA256. The difference with HS512 is the strength of the hash methods themselves. You can take a look at the keylength.com website and this answer. You will see that even SHA-256 has quite a large security margin. What's more, the HMAC algorithm is pretty much oblivious to attacks on the underlying hash algorithm. So even you can use HMAC-SHA1 safely.
Is it even possible to use HS512 encryption with auth0's java JWT?
I took a look at the code, and it is possible (but not documented). Use something similar to
JWTSigner.Options options = new JWTSigner.Options();
options.setAlgorithm(Algorithm.HS512);
jwtSigner.sign(claims, options);
Is it even possible to use HS512 encryption with auth0's java JWT?
You could do something like this:
Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
Example taken from here: link
I am new to cryptography. I want to encrypt the connection string section and some other section in the web.config. I know this can be accomplished using RSACryptoServiceProvider.
But I am not sure about the Key which is being used by the default RSACryptoServiceProvider and the key size.
As per our organization security policy the key size should be 196 bit and we have to share the Key with security team which is used for encryption.
When we use the default encryption what will be key used internally by asp.net for encryption/decryption and the key size?
In-order to use a custom key which can be shared with security team do we need to create a custom class by inhering RSACryptoServiceProvider?
Also RSA Key Container is bit confusing. Is it a container for the Key or the Key itself
Please advice.
RSA key container files which are exported from aspnet_regiis.exe are indeed containers for the key. They are XML files. Actually, as RSA is public key crypto, the key container holds both the public key and private key (if you export both).
When you perform web.config or app.config encryption via aspnet_regiis.exe, and you do not specify a provider, it will use the value of "defaultProvider". See http://msdn.microsoft.com/en-us/library/zhhddkxy(v=vs.100).aspx. The encrypted output will list the provider name (so that you know how to decrypt it). It appears the default name of the default provider is "RsaProtectedConfigurationProvider". That crypto provider uses a key. The default key has a default name of "NetFrameworkConfigurationKey" (see http://blogs.msdn.com/b/mosharaf/archive/2005/11/17/protectedconfiguration.aspx). The key with that name will have a different value on every machine and is generated when .NET is installed.
A key length of 196 bits sounds like your security team expects you to be performing symmetric key encryption (not asymmetric PKC) of some sort. For example, people brag about their AES key lengths being 256 bits. The .NET 4.0 aspnet_regiis.exe command for creating a custom RSA crypto provider and key use a key size of 2048 bits (although 1024 is not uncommon from days of yore). I imagine the default RSA provider and default key use default values for key lengths. But to be sure, you might want to export the default key, and inspect it yourself. The -pc and -px switches and their associated options (like -size) are documented at http://msdn.microsoft.com/en-us/library/vstudio/k6h9cz8h(v=vs.100).aspx.
If you need to be very specific about a private key, which would be durable beyond a machine reimaging, and would be used by many nodes in a server farm, and which needs to be held in escrow by the security team, you probably want to invest the time in creating a non-default crypto provider of the RsaProtectedConfigurationProvider type (not inventing your own CSP class as an alternative to RsaProtectedConfigurationProvider).
One last thing to note, web.config XML encryption is performed in a multi step process. First, the encryption process generates a random symmetric key (which is short in comparison to an RSA key) which will be used to encrypt a plaintext corpus. The plaintext is encrypted with the symmetric key (after the corpus is normalized for whitespace, etc). Then, the symmetric key (which is short compared to the corpus) is encrypted using an RSA public key. If the whole plaintext corpus was encrypted with an RSA public key, it would take a long time to decrypt. So when you look at a block of encrypted XML in a web.config encrypted you will really see two things: an encrypted key section, and an encrypted data section. To decrypt the ciphertext, ASP.NET needs to first decrypt the encrypted symmetric key, and then use the decrypted key to decrypt the stuff you actually want as plaintext.
There is an example of the two-levels of encryption at "Problem with decrypting xml document". What is apparent (and perhaps troubling), is that the RSA crypto provider uses Triple DES in CBC mode for the symmetric crypto algorithm underlying the RSA PKC which you think is really providing the encryption. See this person's frustration around trying to change the symmetric algorithm to AES, for example, Change Microsoft Config File Encryption Method From TripleDES. Triple DES is only recommended for use until 2030 in very ideal scenarios (see http://en.wikipedia.org/wiki/Triple_DES#Security) by the algorithm's endorsers (NIST). NIST had a bake-off years ago for a replacement symmetric algorithm suite, which they have chosen and endorsed as AES (http://en.wikipedia.org/wiki/Advanced_Encryption_Standard). So to use AES-192 or AES-256, you would need to invent your own CSP class as an alternative to RsaProtectedConfigurationProvider, then make it available for creating providers and performing encrypt/decrypt operations from ASP.NET.
Here is another stack-overflow article which is relevant: ASP.NET Encryption - aspnet_regiis - Farm.
Here is a guide to creating/exporting RSA crypto providers and keys for spreading around in a farm, for example: http://msdn.microsoft.com/en-us/library/2w117ede(v=vs.100).aspx
I need to implemented security for client-server communication. I have implemented the following hybrid cryptosystem
To encrypt a message addressed to Alice in a hybrid cryptosystem, Bob does the following:
Obtains Alice's public key.
Generates a fresh symmetric key for the data encapsulation scheme.
Encrypts the message under the data encapsulation scheme, using the symmetric key just generated.
Encrypt the symmetric key under the key encapsulation scheme, using Alice's public key.
Send both of these encryptions to Alice.
To decrypt this hybrid ciphertext, Alice does the following:
uses her private key to decrypt the symmetric key contained in the key encapsulation segment.
uses this symmetric key to decrypt the message contained in the data encapsulation segment.
I am using RSA For a public-key cryptosystem, and AES for symmetric-key cryptosystem. Every thing works fine, but I am not sure how to handle AES initialization vector. Currently, I am concatenating the AES key and initialization vector encrypting it with the public key and sending that to server.
I just wanted to get some opinions about this approach. How this problem is solved by other communication protocols SSL etc.
Thanks.
You don't encrypt the IV. Bundle it with the encrypted key and send it (in the clear) to the recipient.
Standards for this do exist. This scheme is called "KeyTransRecipientInfo" in CMS (upon which S/MIME is based), and PGP offers a similar mode. TLS also includes the initialization vector as a parameter in the key encryption algorithm identifier, using the same ASN.1 syntax as CMS. A robust, open-source library to perform this operation is available for many, many platforms.
At the very least, studying the CMS specification might help avoid some of the many pitfalls in a home-brew implementation. See §6.1 and §6.2.1 of RFC 3369.
I've done the same thing, and I handled it the same way - concatenate the AES key with the IV and encrypt them both.
You could also just send the key and use the key itself to generate an IV - for example by using the first 128 bits of a hash of the key as the IV. That should be OK security-wise as long as you are generating a new AES key for each session and not re-using the same AES key over and over with the same IV.
There is no reason to encrypt the IV - you can send that in the clear. Just make sure you pick a new one each time (the same way you do the AES key).
That said, it is often convenient to package the AES key and IV together. Encryption of 16 bytes ain't that expensive.