internal virtual Option <JObject> EncryptKeyAndBuildResult( IAmazonKeyManagementService kmsClient, string region, string arn, byte[] dataKeyPlainText) { try { TimerOptions encryptTimerOptions = new TimerOptions { Name = MetricsUtil.AelMetricsPrefix + ".kms.aws.encrypt." + region }; using (MetricsUtil.MetricsInstance.Measure.Timer.Time(encryptTimerOptions)) { // Note we can't wipe plaintext key till end of calling method since underlying buffer shared by all requests EncryptRequest encryptRequest = new EncryptRequest { KeyId = arn, Plaintext = new MemoryStream(dataKeyPlainText) }; Task <EncryptResponse> encryptAsync = kmsClient.EncryptAsync(encryptRequest); byte[] encryptedKeyEncryptionKey = encryptAsync.Result.CiphertextBlob.ToArray(); return(Option <JObject> .Some(BuildKmsRegionKeyJson(region, arn, encryptedKeyEncryptionKey))); } } catch (AggregateException e) { Logger.LogWarning(e, "Failed to encrypt generated data key via region {region} KMS", region); // TODO Consider adding notification/CW alert return(Option <JObject> .None); } }
/// <summary> /// Encrypts the provided XML element. /// </summary> /// <param name="plaintextElement">XML element to encrypt.</param> /// <param name="ct">Cancellation token.</param> /// <returns>Encrypted XML data.</returns> #pragma warning disable S3242 // Not altering Microsoft interface definition public async Task <EncryptedXmlInfo> EncryptAsync(XElement plaintextElement, CancellationToken ct) #pragma warning restore S3242 { ValidateConfig(); logger?.LogDebug("Encrypting plaintext DataProtection key using AWS key {0}", Config.KeyId); // Some implementations of this e.g. DpapiXmlEncryptor go to some lengths to create a memory // stream, use unsafe code to pin & zero it, and so on. // // Currently not doing any such zeroing here, as this neglects that the XElement above is in memory, // is a managed construct containing ultimately a System.String, and therefore the plaintext is // already at risk of compromise, copying during GC, paging to disk etc. If we'd been starting with SecureString, // there'd be a good pre-existing case for handling the subsequent memory copies carefully (and it'd // essentially be forced as you can't copy or stream a SecureString without unsafe code). // // Even ignoring that, the subsequent code sending a MemoryStream out over the web to AWS calls ToArray inside // the SDK and then stores the result as a System.String, twice, as part of outgoing JSON, and that's // before considering HTTP-layer buffering... // // Since the AWS code eventually just gets UTF8 byte[] for request content, the ideal would be that // instead of a memory stream and a standard JSON handler, the AWS code prepares all the usual JSON and then // gets a specific UTF8 byte[] entry of the base64 plaintext which a caller can pin and erase (and the SDK could // do the same with its own request content byte[]). // // It doesn't. // // Even then the HttpClient usage would buffer the plaintext enroute. // // In conclusion pinning & zeroing this particular stream seems to be complex & error-prone overkill for // handling data that is already exposed in memory - not that I wouldn't be thrilled to see // a properly reviewed SecureMemoryStream and SecureHttpStreamContent in the framework... // // To at least reduce stream allocation churn & thus copying, pre-allocate a reasonable capacity. using (var memoryStream = new MemoryStream(4096)) { plaintextElement.Save(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); var response = await kmsClient.EncryptAsync(new EncryptRequest { EncryptionContext = ContextUpdater.GetEncryptionContext(Config, dpOptions.Value), GrantTokens = Config.GrantTokens, KeyId = Config.KeyId, Plaintext = memoryStream }, ct) .ConfigureAwait(false); using (var cipherText = response.CiphertextBlob) { var element = new XElement("encryptedKey", new XComment(" This key is encrypted with AWS Key Management Service. "), new XElement("value", Convert.ToBase64String(cipherText.ToArray()))); return(new EncryptedXmlInfo(element, typeof(KmsXmlDecryptor))); } } }
public async Task <string> Encrypt(string data) { using (var stream = GenerateStreamFromString(data)) { var req = new EncryptRequest { Plaintext = stream, KeyId = this.keyId }; var response = await client.EncryptAsync(req); var result = Convert.ToBase64String(response.CiphertextBlob.ToArray()); return(result); } }
public EncryptedValue Encrypt(string value, IOutgoingLogicalMessageContext context) { var encrypted = _client.EncryptAsync(new EncryptRequest { KeyId = _encryptionKeyIdentifier, Plaintext = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(value)) }).GetAwaiter().GetResult(); string base64Value = encrypted != null?Convert.ToBase64String(encrypted.CiphertextBlob.ToArray()) : null; context.Headers[EncryptionHeaders.RijndaelKeyIdentifier] = _encryptionKeyIdentifier; return(new EncryptedValue { EncryptedBase64Value = base64Value }); }
/// <summary> /// Encrypts the passed data with a Master Key. This method will encrypt /// a payload up to a maximum size of 4096 bytes. The master key with the /// specified ID will be used to encrypt the data. /// </summary> /// <param name="keyId">The identifier for the master key.</param> /// <param name="data">The data to encrypt.</param> /// <returns>Encrypted data.</returns> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentException">You must provide some data to encrypt</exception> /// <exception cref="PayloadTooLargeException"></exception> /// <exception cref="KeyManagementServiceUnavailableException"></exception> public byte[] EncryptData(string keyId, byte[] data) { if (_disposed) { throw new ObjectDisposedException("AwsKmsKeyManager"); } ValidateMasterKey(keyId); if (data == null) { throw new ArgumentNullException(nameof(data)); } if (!data.Any()) { throw new ArgumentException("You must provide some data to encrypt", nameof(data)); } if (data.Length > MaxEncryptPayloadSize) { throw new PayloadTooLargeException(MaxEncryptPayloadSize, data.Length); } var res = RetryPolicy.ExecuteAndCapture(() => { using (var msPlainText = new MemoryStream(data)) { var req = new EncryptRequest { KeyId = keyId, Plaintext = msPlainText }; var t = _client.EncryptAsync(req); t.ConfigureAwait(false); return(t.GetAwaiter().GetResult()); } }); ValidateResponse(res); return(((EncryptResponse)res.Result).CiphertextBlob.ToArray()); }
private Amazon.KeyManagementService.Model.EncryptResponse CallAWSServiceOperation(IAmazonKeyManagementService client, Amazon.KeyManagementService.Model.EncryptRequest request) { Utils.Common.WriteVerboseEndpointMessage(this, client.Config, "AWS Key Management Service", "Encrypt"); try { #if DESKTOP return(client.Encrypt(request)); #elif CORECLR return(client.EncryptAsync(request).GetAwaiter().GetResult()); #else #error "Unknown build edition" #endif } catch (AmazonServiceException exc) { var webException = exc.InnerException as System.Net.WebException; if (webException != null) { throw new Exception(Utils.Common.FormatNameResolutionFailureMessage(client.Config, webException.Message), webException); } throw; } }