private byte[] DecodeSignature(Message encryptedMessage, EncryptedMessageHeaders encryptedHeaders) { if (string.IsNullOrWhiteSpace(encryptedHeaders.Signature)) { _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.SignatureVerificationFailure) { Detail = "Missing signature", Message = encryptedMessage }.Build()); throw new MessageEncryptionException("Missing signature"); } byte[] signature; try { signature = Convert.FromBase64String(encryptedHeaders.Signature); } catch (Exception ex) { _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.SignatureVerificationFailure) { Detail = "Error decoding signature", Message = encryptedMessage, Exception = ex }.Build()); throw new MessageEncryptionException("Error decoding signature", ex); } return(signature); }
public async Task <Message> Encrypt(Message message) { byte[] iv; using (var csp = new AesCryptoServiceProvider()) { csp.GenerateIV(); iv = csp.IV; } var headerCleartext = await MarshalHeaders(message.Headers); var contentCleartext = await MarshalContent(message.Content); var headerCiphertext = await Encrypt(iv, headerCleartext); var contentCiphertext = await Encrypt(iv, contentCleartext); var headerSignature = Sign(headerCleartext); var encryptedHeaders = new EncryptedMessageHeaders { // Message ID must be available in cleartext MessageId = message.Headers.MessageId, IV = Convert.ToBase64String(iv), Headers = Convert.ToBase64String(headerCiphertext), Signature = Convert.ToBase64String(headerSignature), SignatureAlgorithm = "HMACSHA256" }; var encryptedContent = Convert.ToBase64String(contentCiphertext); return(new Message(encryptedHeaders, encryptedContent)); }
public async Task <Message> Decrypt(Message encryptedMessage) { var encryptedHeaders = new EncryptedMessageHeaders(encryptedMessage.Headers); var iv = Convert.FromBase64String(encryptedHeaders.IV); var headerCiphertext = Convert.FromBase64String(encryptedHeaders.Headers); var contentCiphertext = Convert.FromBase64String(encryptedMessage.Content); var signature = DecodeSignature(encryptedMessage, encryptedHeaders); var keyNumber = 0; var keyCount = _decryptionKeys.Count; var innerExceptions = new List <Exception>(); foreach (var key in _decryptionKeys) { keyNumber++; byte[] headerCleartext; byte[] contentCleartext; try { headerCleartext = await Decrypt(headerCiphertext, key, iv); } catch (Exception ex) { innerExceptions.Add(ex); _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.DecryptionError) { Detail = $"Error decrypting message headers using key {keyNumber} of {keyCount}", Message = encryptedMessage, Exception = ex }.Build()); continue; } var signatureVerified = false; try { signatureVerified = Verify(key, headerCleartext, signature); if (!signatureVerified) { _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.SignatureVerificationFailure) { Detail = $"Signature verification failed using key {keyNumber} of {keyCount}", Message = encryptedMessage }.Build()); } } catch (Exception ex) { innerExceptions.Add(ex); _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.SignatureVerificationFailure) { Detail = $"Unexpected error verifying message signature using key {keyNumber} of {keyCount}", Message = encryptedMessage, Exception = ex }.Build()); } if (!signatureVerified) { continue; } try { contentCleartext = await Decrypt(contentCiphertext, key, iv); } catch (Exception ex) { innerExceptions.Add(ex); _diagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.DecryptionError) { Detail = $"Error decrypting message content using key {keyNumber} of {keyCount}", Message = encryptedMessage, Exception = ex }.Build()); continue; } var headers = await UnmarshalHeaders(headerCleartext); var content = await UnmarshalContent(contentCleartext); return(new Message(headers, content)); } throw new MessageEncryptionException($"Unable to decrypt and verify message using any of {keyCount} available decryption key(s)", innerExceptions); }