/// <summary>
        /// Fetches a known system key from metastore and decrypts it using the key management service.
        /// </summary>
        ///
        /// <returns>The decrypted system key.</returns>
        ///
        /// <param name="systemKeyMeta">The <see cref="KeyMeta"/> of the system key.</param>
        /// <exception cref="MetadataMissingException">If the system key is not found.</exception>
        internal virtual CryptoKey GetSystemKey(KeyMeta systemKeyMeta)
        {
            EnvelopeKeyRecord systemKeyRecord = LoadKeyRecord(systemKeyMeta.KeyId, systemKeyMeta.Created);

            return(keyManagementService.DecryptKey(
                       systemKeyRecord.EncryptedKey, systemKeyRecord.Created, systemKeyRecord.Revoked.IfNone(false)));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="EnvelopeKeyRecord"/> class using the provided parameters. An
 /// envelope key record is an internal data structure used to represent a system key, intermediate key or a data
 /// row key. It consists of an encrypted key and metadata referencing the parent key in the key hierarchy used
 /// to encrypt it (i.e. its Key Encryption Key).
 /// </summary>
 ///
 /// <param name="created">Creation time of the <paramref name="encryptedKey"/>.</param>.
 /// <param name="parentKeyMeta">The <see cref="KeyMeta"/> for encryption keys.</param>
 /// <param name="encryptedKey">The encrypted key (a system key, intermediate key or a data row key.</param>
 /// <param name="revoked">The revocation status of the encrypted key.</param>
 public EnvelopeKeyRecord(DateTimeOffset created, KeyMeta parentKeyMeta, byte[] encryptedKey, bool?revoked)
 {
     Created       = created;
     ParentKeyMeta = parentKeyMeta;
     EncryptedKey  = encryptedKey;
     Revoked       = revoked ?? Option <bool> .None;
 }
        internal virtual T WithSystemKeyForWrite <T>(Func <CryptoKey, T> functionWithDecryptedSystemKey)
        {
            // Try to get latest from cache. If not found or expired, get latest or create
            CryptoKey systemKey = systemKeyCache.GetLast();

            if (systemKey == null || IsKeyExpiredOrRevoked(systemKey))
            {
                systemKey = GetLatestOrCreateSystemKey();

                // Put the key into our cache if allowed
                if (cryptoPolicy.CanCacheSystemKeys())
                {
                    try
                    {
                        KeyMeta systemKeyMeta = new KeyMeta(partition.SystemKeyId, systemKey.GetCreated());

                        Logger.LogDebug("Attempting to update cache for SK {keyMeta}", systemKeyMeta);
                        systemKey = systemKeyCache.PutAndGetUsable(systemKeyMeta.Created, systemKey);
                    }
                    catch (Exception e)
                    {
                        DisposeKey(systemKey, e);
                        throw new AppEncryptionException("Unable to update cache for SystemKey", e);
                    }
                }
            }

            return(ApplyFunctionAndDisposeKey(systemKey, functionWithDecryptedSystemKey));
        }
        /// <inheritdoc/>
        public virtual byte[] DecryptDataRowRecord(JObject dataRowRecord)
        {
            using (MetricsUtil.MetricsInstance.Measure.Timer.Time(DecryptTimerOptions))
            {
                Json dataRowRecordJson = new Json(dataRowRecord);

                Json   keyDocument      = dataRowRecordJson.GetJson("Key");
                byte[] payloadEncrypted = dataRowRecordJson.GetBytes("Data");

                EnvelopeKeyRecord dataRowKeyRecord = new EnvelopeKeyRecord(keyDocument);

                KeyMeta keyMeta = dataRowKeyRecord.ParentKeyMeta.IfNone(() =>
                                                                        throw new MetadataMissingException("Could not find parentKeyMeta {IK} for dataRowKey"));

                if (!partition.IsValidIntermediateKeyId(keyMeta.KeyId))
                {
                    throw new MetadataMissingException("Could not find parentKeyMeta {IK} for dataRowKey");
                }

                byte[] decryptedPayload = WithIntermediateKeyForRead(
                    keyMeta,
                    intermediateCryptoKey =>
                    crypto.EnvelopeDecrypt(
                        payloadEncrypted, dataRowKeyRecord.EncryptedKey, dataRowKeyRecord.Created, intermediateCryptoKey));

                return(decryptedPayload);
            }
        }
        /// <summary>
        /// Fetches a known intermediate key from metastore and decrypts it using its associated system key.
        /// </summary>
        ///
        /// <returns>The decrypted intermediate key.</returns>
        ///
        /// <param name="intermediateKeyMeta">The <see cref="KeyMeta"/> of intermediate key.</param>
        /// <exception cref="MetadataMissingException">If the intermediate key is not found, or it has missing system
        /// key info.</exception>
        internal virtual CryptoKey GetIntermediateKey(KeyMeta intermediateKeyMeta)
        {
            EnvelopeKeyRecord intermediateKeyRecord = LoadKeyRecord(intermediateKeyMeta.KeyId, intermediateKeyMeta.Created);

            return(WithExistingSystemKey(
                       intermediateKeyRecord.ParentKeyMeta.IfNone(() =>
                                                                  throw new MetadataMissingException("Could not find parentKeyMeta (SK) for intermediateKey")),
                       false,
                       key => DecryptKey(intermediateKeyRecord, key)));
        }
Exemple #6
0
        /// <inheritdoc/>
        public override bool Equals(object obj)
        {
            if (this == obj)
            {
                return(true);
            }

            if (obj == null || GetType() != obj.GetType())
            {
                return(false);
            }

            KeyMeta other = (KeyMeta)obj;

            return(Equals(KeyId, other.KeyId) &&
                   Equals(Created, other.Created));
        }
        /// <summary>
        /// Calls a function using a decrypted system key that was previously used.
        /// </summary>
        /// <typeparam name="T">The type that the <paramref name="functionWithSystemKey"/> returns.</typeparam>
        ///
        /// <returns>The result returned by the <paramref name="functionWithSystemKey"/>.</returns>
        ///
        /// <param name="systemKeyMeta">system key meta used previously to write an IK.</param>
        /// <param name="treatExpiredAsMissing">if <value>true</value>, will throw a
        /// <see cref="MetadataMissingException"/> if the key is expired/revoked.</param>
        /// <param name="functionWithSystemKey">the function to call using the decrypted system key.</param>
        ///
        /// <exception cref="MetadataMissingException">If the system key is not found, or if its expired/revoked and
        /// <see cref="treatExpiredAsMissing"/> is <value>true</value>.</exception>
        internal virtual T WithExistingSystemKey <T>(
            KeyMeta systemKeyMeta, bool treatExpiredAsMissing, Func <CryptoKey, T> functionWithSystemKey)
        {
            // Get from cache or lookup previously used key
            CryptoKey systemKey = systemKeyCache.Get(systemKeyMeta.Created);

            if (systemKey == null)
            {
                systemKey = GetSystemKey(systemKeyMeta);

                // Put the key into our cache if allowed
                if (cryptoPolicy.CanCacheSystemKeys())
                {
                    try
                    {
                        Logger.LogDebug("Attempting to update cache for SK {keyMeta}", systemKeyMeta);
                        systemKey = systemKeyCache.PutAndGetUsable(systemKeyMeta.Created, systemKey);
                    }
                    catch (Exception e)
                    {
                        DisposeKey(systemKey, e);
                        throw new AppEncryptionException("Unable to update cache for SystemKey", e);
                    }
                }
            }

            if (IsKeyExpiredOrRevoked(systemKey))
            {
                if (treatExpiredAsMissing)
                {
                    DisposeKey(systemKey, null);
                    throw new MetadataMissingException("System key is expired/revoked, keyMeta = " + systemKeyMeta);
                }

                // There's an implied else here
                if (cryptoPolicy.NotifyExpiredSystemKeyOnRead())
                {
                    // TODO: Send notification that an SK is expired
                    Logger.LogDebug("NOTIFICATION: Expired SK {keyMeta} in use during read", systemKeyMeta);
                }
            }

            return(ApplyFunctionAndDisposeKey(systemKey, functionWithSystemKey));
        }
        /// <inheritdoc/>
        public virtual JObject EncryptPayload(byte[] payload)
        {
            using (MetricsUtil.MetricsInstance.Measure.Timer.Time(EncryptTimerOptions))
            {
                EnvelopeEncryptResult result = WithIntermediateKeyForWrite(intermediateCryptoKey => crypto.EnvelopeEncrypt(
                                                                               payload,
                                                                               intermediateCryptoKey,
                                                                               new KeyMeta(partition.IntermediateKeyId, intermediateCryptoKey.GetCreated())));

                KeyMeta parentKeyMeta = (KeyMeta)result.UserState;

                EnvelopeKeyRecord keyRecord =
                    new EnvelopeKeyRecord(DateTimeOffset.UtcNow, parentKeyMeta, result.EncryptedKey);

                Json wrapperDocument = new Json();
                wrapperDocument.Put("Key", keyRecord.ToJson());
                wrapperDocument.Put("Data", result.CipherText);

                return(wrapperDocument.ToJObject());
            }
        }
        /// <summary>
        /// Calls a function using a decrypted intermediate key that was previously used.
        /// </summary>
        /// <typeparam name="T">The type that the <paramref name="functionWithIntermediateKey"/> returns.</typeparam>
        ///
        /// <returns>The result returned by the <paramref name="functionWithIntermediateKey"/>.</returns>
        ///
        /// <param name="intermediateKeyMeta">intermediate key meta used previously to write a DRR.</param>
        /// <param name="functionWithIntermediateKey">the function to call using the decrypted intermediate key.</param>
        ///
        /// <exception cref="MetadataMissingException">If the intermediate key is not found, or it has missing system
        /// key info.</exception>
        internal virtual T WithIntermediateKeyForRead <T>(
            KeyMeta intermediateKeyMeta, Func <CryptoKey, T> functionWithIntermediateKey)
        {
            // Get from cache or lookup previously used key
            CryptoKey intermediateKey = intermediateKeyCache.Get(intermediateKeyMeta.Created);

            if (intermediateKey == null)
            {
                intermediateKey = GetIntermediateKey(intermediateKeyMeta.Created);

                // Put the key into our cache if allowed
                if (cryptoPolicy.CanCacheIntermediateKeys())
                {
                    try
                    {
                        Logger.LogDebug(
                            "Attempting to update cache for IK {keyId} with created {created}",
                            partition.IntermediateKeyId,
                            intermediateKey.GetCreated());
                        intermediateKey = intermediateKeyCache.PutAndGetUsable(intermediateKey.GetCreated(), intermediateKey);
                    }
                    catch (Exception e)
                    {
                        DisposeKey(intermediateKey, e);
                        throw new AppEncryptionException("Unable to update cache for Intermediate key", e);
                    }
                }
            }

            if (cryptoPolicy.NotifyExpiredIntermediateKeyOnRead() && IsKeyExpiredOrRevoked(intermediateKey))
            {
                // TODO :  Send notification that a DRK is using an expired IK
                Logger.LogDebug("NOTIFICATION: Expired IK {keyMeta} in use during read", intermediateKeyMeta);
            }

            return(ApplyFunctionAndDisposeKey(intermediateKey, functionWithIntermediateKey));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="EnvelopeKeyRecord"/> class using the provided parameters. An
 /// envelope key record is an internal data structure used to represent a system key, intermediate key or a data
 /// row key. It consists of an encrypted key and metadata referencing the parent key in the key hierarchy used
 /// to encrypt it (i.e. its Key Encryption Key).
 /// </summary>
 ///
 /// <param name="created">Creation time of the <paramref name="encryptedKey"/>.</param>.
 /// <param name="parentKeyMeta">The <see cref="KeyMeta"/> for encryption keys.</param>
 /// <param name="encryptedKey">The encrypted key (a system key, intermediate key or a data row key.</param>
 public EnvelopeKeyRecord(DateTimeOffset created, KeyMeta parentKeyMeta, byte[] encryptedKey)
     : this(created, parentKeyMeta, encryptedKey, null)
 {
 }