I am writing a test application for Microsoft CryptoAPI. I want to export the secret key of one party using the public key of the second party, and then import that secret key as the second party's secret key (this sets up a shared secret key for communication). Here is my code:
if(!CryptExportKey(encryptT->hSymKey, decryptT->hPubKey, SIMPLEBLOB, 0, keyExBuf, &bufLen)) {
FormattedDebugPrint(NULL, GetLastError(), "could not export secret key", TRUE);
return -1;
}
if(!CryptImportKey(decryptT->hCryptProv, keyExBuf, bufLen, decryptT->hPubKey, 0, &(decryptT->hSymKey))) {
FormattedDebugPrint(NULL, GetLastError(), "could not import secret key", TRUE);
return -1;
}
And this gives the error:
80090001: Bad UID.
The public keypair is being generated for both encryptT and decryptT (sender, receiver) by calling:
CryptGenKey(encryptT->hCryptProv, CALG_RSA_KEYX, CRYPT_EXPORTABLE, &(encryptT->hPubKey))
Any idea what could be causing the error?
Thanks,
Never mind, I figured it out. Basically, you can't just use another public key directly even if it's initialized the same way -- I needed to first export that public key, and then import it using the handle to the cryptographic provider of the other party.
Related
I have .NET Framework application where I try to read data from AWS parameter store using AmazonSimpleSystemsManagementClient on my local environment. Besides I have credentials generated by AWS CLI and located in
Users/MyUser/.aws
folder. When I try to connect to the parameter store from CMD using the creds it works fine. Though the AmazonSimpleSystemsManagementClient in the application with default constructor, it throws exception "Unable to get IAM security credentials from EC2 Instance Metadata Service." When I tried to pass BasicAWSParameters to the client with hardcoded working keys I got another exception "The security token included in the request is invalid".
Also I tried installing EC2Config, initializing AWS SDK Store from Visual Studio AWS Toolkit. Though it didn't change the game.
I would want to avoid using environment variables or hardcoding the keys since keys are generated and valid only 1 hour. Then I should regenerate so copying them somewhere every time is not convenient for me.
Please advice how to resolve the issue.
Some code
_client = new AmazonSimpleSystemsManagementClient()
public string GetValue(string key)
{
if (_client == null)
return null;
var request = new GetParameterRequest
{
Name = $"{_baseParameterPath}/{key}",
WithDecryption = true,
};
try
{
var response = _client.GetParameterAsync(request).Result;
return response.Parameter.Value;
}
catch (Exception exc)
{
return null;
}
}
credentials file looks as following (I removed key values not to expose):
[default]
aws_access_key_id= KEY VALUE
aws_secret_access_key= KEY VALUE
aws_session_token= KEY VALUE
[MyProfile]
aws_access_key_id= KEY VALUE
aws_secret_access_key= KEY VALUE
aws_session_token= KEY VALUE
As long as you have your creds in .aws/credentials, you can create the Service client and the creds will be located and used. No need to create a BasicAWSParameters object.
Creds in a file named credentials:
[default]
aws_access_key_id=Axxxxxxxxxxxxxxxxxxxxxxxxxxx
aws_secret_access_key=/zxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
This .NET code works.
using System;
using System.Threading.Tasks;
using Amazon.SimpleSystemsManagement;
using Amazon.SimpleSystemsManagement.Model;
namespace ConsoleApp1 {
class Program {
static async Task Main(string[] args) {
var client = new AmazonSimpleSystemsManagementClient();
var request = new GetParameterRequest()
{
Name = "RDSConnection"
};
var response = client.GetParameterAsync(request).GetAwaiter().GetResult();
Console.WriteLine("Parameter value is " + response.Parameter.Value);
}
}
}
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.
Using dart-lang/gcloud to read and write files to Google Cloud Storage, is it possible to provide customer-supplied encryption keys?
The Dart gcloud library is built upon dart-lang/googleapis which itself is interfaces with the Cloud Storage REST API, but the HTTP client it uses is so abstracted that it's hard to tell how to set the headers necessary for custom encryption.
Currently there is no support for custom encryption keys in package:gcloud.
Though the Storage constructor accepts an http.Client. So you can supply your own client which adds the headers, something along the lines of:
import 'package:http/http.dart' as http;
import 'package:gcloud/storage.dart' as storage;
class ClientWithKeys extends http.client {
final String encryptionAlgorithm;
final String encryptionKey;
final String encryptionSHA256;
ClientWithKeys(this.encriptionAlgorithm,
this.encriptionKey,
this.encryptionSHA256);
Future<StreamedResponse> send(request) {
request.headers['x-goog-encryption-algorithm'] = encryptionAlgorithm;
request.headers['x-goog-encryption-key'] = encryptionKey;
request.headers['x-goog-encryption-key-sha256'] = encryptionSHA256;
return super.send(request);
}
}
code() {
final client = new ClientWithKeys('<algo>', '<key>', '<sha256>');
final api = new storage.Storage(client, '<project-id>');
...
client.close();
}
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.
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.