private byte[] UnprotectCore(byte[] protectedData, bool allowOperationsOnRevokedKeys, out UnprotectStatus status) { Debug.Assert(protectedData != null); try { // argument & state checking if (protectedData.Length < sizeof(uint) /* magic header */ + sizeof(Guid) /* key id */) { // payload must contain at least the magic header and key id throw Error.ProtectionProvider_BadMagicHeader(); } // Need to check that protectedData := { magicHeader || keyId || encryptorSpecificProtectedPayload } // Parse the payload version number and key id. uint magicHeaderFromPayload; Guid keyIdFromPayload; fixed(byte *pbInput = protectedData) { magicHeaderFromPayload = ReadBigEndian32BitInteger(pbInput); keyIdFromPayload = Read32bitAlignedGuid(&pbInput[sizeof(uint)]); } // Are the magic header and version information correct? int payloadVersion; if (!TryGetVersionFromMagicHeader(magicHeaderFromPayload, out payloadVersion)) { throw Error.ProtectionProvider_BadMagicHeader(); } else if (payloadVersion != 0) { throw Error.ProtectionProvider_BadVersion(); } if (_logger.IsDebugLevelEnabled()) { _logger.PerformingUnprotectOperationToKeyWithPurposes(keyIdFromPayload, JoinPurposesForLog(Purposes)); } // Find the correct encryptor in the keyring. bool keyWasRevoked; var currentKeyRing = _keyRingProvider.GetCurrentKeyRing(); var requestedEncryptor = currentKeyRing.GetAuthenticatedEncryptorByKeyId(keyIdFromPayload, out keyWasRevoked); if (requestedEncryptor == null) { _logger?.KeyWasNotFoundInTheKeyRingUnprotectOperationCannotProceed(keyIdFromPayload); throw Error.Common_KeyNotFound(keyIdFromPayload); } // Do we need to notify the caller that he should reprotect the data? status = UnprotectStatus.Ok; if (keyIdFromPayload != currentKeyRing.DefaultKeyId) { status = UnprotectStatus.DefaultEncryptionKeyChanged; } // Do we need to notify the caller that this key was revoked? if (keyWasRevoked) { if (allowOperationsOnRevokedKeys) { _logger?.KeyWasRevokedCallerRequestedUnprotectOperationProceedRegardless(keyIdFromPayload); status = UnprotectStatus.DecryptionKeyWasRevoked; } else { _logger?.KeyWasRevokedUnprotectOperationCannotProceed(keyIdFromPayload); throw Error.Common_KeyRevoked(keyIdFromPayload); } } // Perform the decryption operation. ArraySegment <byte> ciphertext = new ArraySegment <byte>(protectedData, sizeof(uint) + sizeof(Guid), protectedData.Length - (sizeof(uint) + sizeof(Guid))); // chop off magic header + encryptor id ArraySegment <byte> additionalAuthenticatedData = new ArraySegment <byte>(_aadTemplate.GetAadForKey(keyIdFromPayload, isProtecting: false)); // At this point, cipherText := { encryptorSpecificPayload }, // so all that's left is to invoke the decryption routine directly. return(requestedEncryptor.Decrypt(ciphertext, additionalAuthenticatedData) ?? CryptoUtil.Fail <byte[]>("IAuthenticatedEncryptor.Decrypt returned null.")); } catch (Exception ex) when(ex.RequiresHomogenization()) { // homogenize all failures to CryptographicException throw Error.DecryptionFailed(ex); } }
private byte[] UnprotectCore(byte[] protectedData, bool allowOperationsOnRevokedKeys, out UnprotectStatus status) { Debug.Assert(protectedData != null); try { // argument & state checking if (protectedData.Length < sizeof(uint) /* magic header */ + sizeof(Guid) /* key id */) { // payload must contain at least the magic header and key id throw Error.ProtectionProvider_BadMagicHeader(); } // Need to check that protectedData := { magicHeader || keyId || encryptorSpecificProtectedPayload } // Parse the payload version number and key id. uint magicHeaderFromPayload; Guid keyIdFromPayload; fixed (byte* pbInput = protectedData) { magicHeaderFromPayload = ReadBigEndian32BitInteger(pbInput); keyIdFromPayload = Read32bitAlignedGuid(&pbInput[sizeof(uint)]); } // Are the magic header and version information correct? int payloadVersion; if (!TryGetVersionFromMagicHeader(magicHeaderFromPayload, out payloadVersion)) { throw Error.ProtectionProvider_BadMagicHeader(); } else if (payloadVersion != 0) { throw Error.ProtectionProvider_BadVersion(); } if (_logger.IsDebugLevelEnabled()) { _logger.LogDebugF($"Performing unprotect operation to key {keyIdFromPayload:B} with purposes {JoinPurposesForLog(Purposes)}."); } // Find the correct encryptor in the keyring. bool keyWasRevoked; var currentKeyRing = _keyRingProvider.GetCurrentKeyRing(); var requestedEncryptor = currentKeyRing.GetAuthenticatedEncryptorByKeyId(keyIdFromPayload, out keyWasRevoked); if (requestedEncryptor == null) { if (_logger.IsDebugLevelEnabled()) { _logger.LogDebugF($"Key {keyIdFromPayload:B} was not found in the key ring. Unprotect operation cannot proceed."); } throw Error.Common_KeyNotFound(keyIdFromPayload); } // Do we need to notify the caller that he should reprotect the data? status = UnprotectStatus.Ok; if (keyIdFromPayload != currentKeyRing.DefaultKeyId) { status = UnprotectStatus.DefaultEncryptionKeyChanged; } // Do we need to notify the caller that this key was revoked? if (keyWasRevoked) { if (allowOperationsOnRevokedKeys) { if (_logger.IsVerboseLevelEnabled()) { _logger.LogVerboseF($"Key {keyIdFromPayload:B} was revoked. Caller requested unprotect operation proceed regardless."); } status = UnprotectStatus.DecryptionKeyWasRevoked; } else { if (_logger.IsVerboseLevelEnabled()) { _logger.LogVerboseF($"Key {keyIdFromPayload:B} was revoked. Unprotect operation cannot proceed."); } throw Error.Common_KeyRevoked(keyIdFromPayload); } } // Perform the decryption operation. ArraySegment<byte> ciphertext = new ArraySegment<byte>(protectedData, sizeof(uint) + sizeof(Guid), protectedData.Length - (sizeof(uint) + sizeof(Guid))); // chop off magic header + encryptor id ArraySegment<byte> additionalAuthenticatedData = new ArraySegment<byte>(_aadTemplate.GetAadForKey(keyIdFromPayload, isProtecting: false)); // At this point, cipherText := { encryptorSpecificPayload }, // so all that's left is to invoke the decryption routine directly. return requestedEncryptor.Decrypt(ciphertext, additionalAuthenticatedData) ?? CryptoUtil.Fail<byte[]>("IAuthenticatedEncryptor.Decrypt returned null."); } catch (Exception ex) when (ex.RequiresHomogenization()) { // homogenize all failures to CryptographicException throw Error.DecryptionFailed(ex); } }