Can I use JWT to exchange a private key ?
I must use this private key to decrypt earlier encrypted data. I use TLS to exchange information between the server and client. Is secure ? It is a valid idea to exchange the key ?
Example:
Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"private_key": Base64(generated private key)
}
Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
passphrase
)
When a secured communication is established, each stakeholder generates/has its own private key. Only public keys are exchanged. Private key exchange should be prevented.
Anyway, if you you really need to send a private key through the JWT format, then you should read about the JSON Web Key (JWK) specification (RFC7517) section 7.
The process is quite simple: create a JWE with the JWK as payload and mandatory headers plus the (optional) cty header parameter with value jwk+json.
Example:
JWE Header:
{
"alg":"A256KW",
"enc":"A256GCM",
"cty":"jwk+json"
}
JWE Payload (the JWK):
{
"kty":"oct",
"alg":"A128KW",
"k":"GawgguFyGrWKav7AX4VKUg"
}
Related
I am trying to add encryption to my chat application . but facing an issue while doing so , i cant
add the data to firebase , it shows an error Unhandled Exception: Invalid argument: Instance of 'Encrypted'. how can i send a message that is encrypted from client side and send it to firebase and then receive the message , then decrypt it . because i am using the library encrypt 5.0.0 for this and to decrypt it , it only accept the Encrypted as parameter .
here is class for encryption and decryption .
import 'package:encrypt/encrypt.dart' as encrypt;
class MyEncryptionDecryption{
///for encrption
static final key = encrypt.Key.fromLength(32);
static final iv = encrypt.IV.fromLength(16);
static final encrypter = encrypt.Encrypter(encrypt.AES(key));
static encryptAES(message ){
final encrypted = encrypter.encrypt(message ,iv: iv);
print(encrypted.base16);
print(encrypted.base64);
return encrypted;
}
static decryptedAES(message){
return encrypter.decrypt(message,iv: iv);
}
}
using it to send message to firebase as this ..
var aes = MyEncryptionDecryption.encryptAES(message);
Map<String, dynamic> messageInfoMap = {
"message": aes,
"sendBy": myUserName,
"ts": lastMessageTs,
"imgUrl": myProfilePic
};
DatabaseMethods()
.addMessage(chatRoomId, messageId, messageInfoMap)
.then((value) {
Map<String, dynamic> lastMessageInfoMap = {
"lastMessage": aes,
"lastMessageSendTs": lastMessageTs,
"lastMessageSendBy": myUserName,
"readStatus" : false ,
"count" : count,
"show" : true,
};
DatabaseMethods().updateLastMessageSend(chatRoomId, lastMessageInfoMap);
and here are the Database functions ..
Future addMessage(String chatRoomId , String messageId,messageInfoMap) async {
return await FirebaseFirestore.instance.
collection("chatrooms").
doc(chatRoomId).collection('chats').doc(messageId).set(messageInfoMap);
}
updateLastMessageSend(String chatRoomId, lastMessageInfoMap){
return FirebaseFirestore
.instance.collection('chatrooms').doc(chatRoomId)
.update(lastMessageInfoMap);
}
Encrypted is an object. You can retrieve actual value using the fields defined in the API of Encrypted, e.g. the property bytes to get the byte representation of the object or base64 if you require the ciphertext as text.
Of course, you can revert back to Encrypted using one of the constructors: just the Encrypted constructor for bytes or fromBase64 for text.
Here's something I don't understand.
I've played with some code examples on how to encrypt a string in the browser and decrypt the ciphered text on the server and I don't see how this is secure at all.
All of the examples assume that the same iv and the key used to encrypt the string will be sent to the server so it knows how to decrypt it.
Isn't that like taping the keys to the safe?
Am I supposed to send the iv and key object with the payload, along with the encrypted string?
I have to be missing something here.
async function generateKey() {
return await window.crypto.subtle.generateKey({
name: "AES-CBC",
length: 256
},
false,
["encrypt", "decrypt"]);
}
async function encryptString(data, key, iv) {
return await window.crypto.subtle.encrypt(
{
name: "AES-CBC",
iv,
},
key,
data
);
}
async function decryptString(data, key, iv) {
const decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-CBC",
iv,
},
key,
data
);
return new TextDecoder("utf-8").decode(new Uint8Array(decrypted));
}
async function example() {
try {
// Create the IV and Key
const iv = window.crypto.getRandomValues(new Uint8Array(16));
const key = await generateKey();
// Convert the string I want to encrypt into an ArrayBuffer
const data = new TextEncoder("utf-8").encode('Hello World!');
// Encrypt the ArrayBuffer
const ciphertext = await encryptString(data, key, iv);
console.log(ciphertext);
// Now I decrypt the obscured string using the same key and iv I used to encrypt it.
const decrypted = await decryptString(ciphertext, key, iv);
// Hello World!
console.log(decrypted);
} catch(error) {
console.log(error);
}
}
Actually, the Symmetric Key between browser and server must be established using Asymmetric key first.
Like HTTS (TLS or SSL) is encrypted channel using Asymmetric key (Public key at Browser and Private key at server).
Thus you may rely on Encrypted Channel using HTTPS (TLS) to protect your Symmetric keys or alternatively, you may develop your own mechanism to protect it using Asymmetric keys, for which you will have to generate pair of keys (common for all users - at server or for every user), publish public key to clients and clients will use that public key to encrypt Symmetric key (and iv) which you will decrypt using server side private key. Once Asymmetric key is established, you can use it for fixed duration as per security requirements and then repeat the process, say after every 1 hour or 6 hours or 24 hours, etc.
I am working on an ASP.NET 5 app and I would like to use JWTs to secure certain endpoints in the application. For the time being we have decided that we (as opposed to a third party) will issue the JWTs, as all of our clients are 'owned' by the application, i.e. we have no 'external' clients. In the example, I have an endpoint which creates and returns a JWT using the jwt-dotnet library as follows (I appreciate that this is a basic example, with no expiration time and a single subject claim etc.):
...
// include a single subject claim (user id)
var claims = new Dictionary<string, object>() { { "sub", "1234" } };
var key = "EXAMPLE_SECRET_KEY_TO_SIGN_JWT";
var token = JWT.JsonWebToken.Encode(claims, key, JWT.JwtHashAlgorithm.HS256);
...
// return JWT
I can encode, and decode this JWT using the same key as one would expect. In my Startup.cs file, I am using Microsoft.AspNet.Authentication.OAuthBearer middleware to Authorize the relevant routes in my controllers which have the [Authorize] attribute specified. However, after looking at a number of posts including here and here I cannot seem to find an example of how to supply this signing key to the OAuth middleware in the same fashion. The code in my Startup.cs file looks as follows:
public class Startup
{
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseErrorPage();
app.UseOAuthBearerAuthentication();
app.UseMvc();
}
...
public void ConfigureServices(IServiceCollection services)
{
services.Configure<OAuthBearerAuthenticationOptions>(bearer =>
{
bearer.AutomaticAuthentication = true;
bearer.TokenValidationParameters.ValidAudience = "Example audience";
bearer.TokenValidationParameters.ValidIssuer = "Example issuer";
bearer.TokenValidationParameters.ValidateAudience = true;
bearer.TokenValidationParameters.ValidateIssuer = true;
bearer.TokenValidationParameters... // how do I set the signing key as a string literal?
});
services.AddMvc();
}
}
My assumption has been that I should be able to simply supply the same string literal key to the middleware so it can validate the token signature. However this does not seem to be the case, as the examples discuss using RSA keys or certificates as opposed to providing a single key/string literal.
I appreciate that I may be missing something here, or indeed that this may be the wrong approach and I should't be able to do this!
EDIT: symmetric keys are now natively supported in the RC2 nightly builds:
var key = Convert.FromBase64String("base64-encoded symmetric key");
app.UseJwtBearerAuthentication(options => {
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.Authority = Configuration["jwt:authority"];
options.Audience = Configuration["jwt:audience"];
options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(key);
});
You can't, at least not without a bit of plumbing: the OAuth2 bearer middleware relies on IdentityModel 5, that doesn't support symmetric keys like the one you're using in your first snippet.
Of course, symmetric keys will be eventually supported (https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/250), but in the meantime, using an asymmetric key (like a RSA key) is recommended.
You can also implement symmetric keys support yourself (see https://gist.github.com/sandorfr/4039d540b6b552154522), but using a RSA key is definitely a better option.
I read a simplification about how public and private keys work on security.stackexchange.com: How can I explain the concept of public and private keys without technical jargon?.
Whatever I understood from there: private key sat at owner and owner send a encrypted data to some one along with public key. Public key decrypts that data at client side and also encrypt data of client sent to owner. Once the data is encrypted at client side by public key then the same public key can not reused to encrypt that data. Only the owner of the private key can encrypt and decrypt data as many as time.
Am I right whatever I understood?
My question is: how public key is travel from owner side to client side?
Every time the same public key will be sent from server end to client end or ever time the different public key will be send from server end to client end?
#Ewan said as follows:
Client : Sends "Hello"
Server : Here is my public key
Server : Please send your public key
Client : Here is my (encrypted with server public key)public key
Client : Here is an (encrypted with server public key)request
Server : Here is an (encrypted with client public key)response
This raises the following questions at said steps:
When first time client send Hello to server then how hello
will travel to server in encrypted way?
Do not understand why server find his public key?
Why server request client to send his public key?
No you are wrong:
PersonA : creates public and private key pair
PersonA : Sends Public Key(A) to PersonB
PersonB : Encrypts data with Public Key(A)
PersonB : Sends encrypted Data to PersonA
PersonA : Decrypts encrypted Data with Private Key(A)
WCF can be setup to do multiple types of encryption and protocols but essentialy what i think you are asking boils down to
Handshake protocol:
Client : Sends "Hello" (not encrypted)
Server : Here is my public key (ServerPublicKEY = "123")
Server : Please send your public key
Client : Here is my public key (ClientPublicKEY = "ABC")
Client : Here is an (encrypted with ServerPublicKEY)request
Server : Decrypt with server private key and read
Server : Here is an (encrypted with ClientPublicKEY)response
Client : decrypt with client private key
to answer your additional questions
q1: "When first time client send Hello to server then how hello will travel to server in encrypted way?"
a1: It is not encrypted
q2: "Do not understand why server find his public key?"
a2: the server sends a public key so that the client can encrypt messages to send to the server
q3: "Why server request client to send his public key?"
a3: The server needs the clients public key so it can encrypt messages to send to the client
So a UserManager has a function called GenerateUserTokenAsync(string purpose, TKey userId).
What does this do in ASP Identity? Can I use this to generate OAuth Bearer tokens? Also what is the purpose parameter for? What values can this be?
UserManager.GenerateUserTokenAsync(User, TokenProvider, Purpose)
can be used to generate Tokens for purposes that are not implemented be the UserManager.
One example could be an invitation system. In a WebProject you need to create a TokenProvider like this:
public class InvitationTokenProvider<TUser> : DataProtectorTokenProvider<TUser> where TUser : class
{
public InvitationTokenProvider(IDataProtectionProvider dataProtectionProvider, IOptions<InvitationTokenProviderOptions> options, ILogger<DataProtectorTokenProvider<TUser>> logger) : base(dataProtectionProvider, options, logger)
{
}
}
and the InvitationTokenProviderOptions
public class InvitationTokenProviderOptions : DataProtectionTokenProviderOptions
{
}
then you can register it in StartUp.ConfigureServices().
services.AddIdentity<User, Role>(options =>
{
// ...
}).AddEntityFrameworkStores<ApplicationDbContect>()
.AddDefaultTokenProviders()
.AddTokenProvider<InvitationTokenProvider<User>>("Invitation");
Afterwards you can use it with the UserManger like this
// create a token
string token = await _userManager.GenerateUserTokenAsync(user, "Invitation", "Invitation");
// verify it
bool result = await _userManager.VerifyUserTokenAsync(user, "Invitation", "Invitation", token);
If you are going to use the token in URLs, don't forget to make it URL-Safe (it may contain '/' and other symbols.
Also check if trailing '==' is lost on the way through emails and browsers.
Documentation for 'GenerateUserTokenAsync' says
Get a user token for a specific purpose
This method should not be used directly, (no idea why it is public). It is used in generating password reset token (GeneratePasswordResetTokenAsync) and email confirmation tokens (GenerateEmailConfirmationTokenAsync). And it is used like this:
GenerateUserTokenAsync("Confirmation", userId); // email confirmation
GenerateUserTokenAsync("ResetPassword", userId); // password reset
In default implementation of token provider (TotpSecurityStampBasedTokenProvider) purpose is used as some sort of password in cryptographic token generation.
Overall, you don't need to use GenerateUserTokenAsync, just call GeneratePasswordResetTokenAsync or GenerateEmailConfirmationTokenAsync.