Re: Internal key management system

From: Sehrope Sarkuni <sehrope(at)jackdb(dot)com>
To: Masahiko Sawada <masahiko(dot)sawada(at)2ndquadrant(dot)com>
Cc: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, cary huang <hcary328(at)gmail(dot)com>, "Moon, Insung" <tsukiwamoon(dot)pgsql(at)gmail(dot)com>, Ibrar Ahmed <ibrar(dot)ahmad(at)gmail(dot)com>, Joe Conway <mail(at)joeconway(dot)com>, Bruce Momjian <bruce(dot)momjian(at)enterprisedb(dot)com>
Subject: Re: Internal key management system
Date: 2020-02-05 13:28:22
Message-ID: CAH7T-aqisSLFWbzgUNa6JUWWZqzfX8Li_VXC8j_N-Opdcfv_Tg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Sat, Feb 1, 2020 at 7:02 PM Masahiko Sawada <
masahiko(dot)sawada(at)2ndquadrant(dot)com> wrote:
> On Sun, 2 Feb 2020 at 00:37, Sehrope Sarkuni <sehrope(at)jackdb(dot)com> wrote:
> >
> > On Fri, Jan 31, 2020 at 1:21 AM Masahiko Sawada
> > <masahiko(dot)sawada(at)2ndquadrant(dot)com> wrote:
> > > On Thu, 30 Jan 2020 at 20:36, Sehrope Sarkuni <sehrope(at)jackdb(dot)com>
wrote:
> > > > That
> > > > would allow the internal usage to have a fixed output length of
> > > > LEN(IV) + LEN(HMAC) + LEN(DATA) = 16 + 32 + 64 = 112 bytes.
> > >
> > > Probably you meant LEN(DATA) is 32? DATA will be an encryption key for
> > > AES256 (master key) internally generated.
> >
> > No it should be 64-bytes. That way we can have separate 32-byte
> > encryption key (for AES256) and 32-byte MAC key (for HMAC-SHA256).
> >
> > While it's common to reuse the same 32-byte key for both AES256 and an
> > HMAC-SHA256 and there aren't any known issues with doing so, when
> > designing something from scratch it's more secure to use entirely
> > separate keys.
>
> The HMAC key you mentioned above is not the same as the HMAC key
> derived from the user provided passphrase, right? That is, individual
> key needs to have its IV and HMAC key. Given that the HMAC key used
> for HMAC(IV || ENCRYPT(KEY, IV, DATA)) is the latter key (derived from
> passphrase), what will be the former key used for?

It's not derived from the passphrase, it's unlocked by the passphrase
(along with the master encryption key). The server will have 64-bytes of
random data, saved encrypted in pg_control, which can be treated as two
separate 32-byte keys, let's call them master_encryption_key and
master_mac_key. The 64-bytes is unlocked by decrypting it with the user
passphrase at startup (which itself would be split into a pair of
encryption and MAC keys to do the unlocking).

The wrap and unwrap operations would use both keys:

wrap(plain_text, encryption_key, mac_key) {
// Generate random IV:
iv = pg_strong_random(16);
// Encrypt:
cipher_text = encrypt_aes256_cbc(encryption_key, iv, plain_text);
// Compute MAC on all inputs:
mac = hmac_sha256(mac_key, encryption_key || iv || cipher_text);
// Concat user facing pieces together
wrapped = mac || iv || cipher_text;
return wrapped;
}

unwrap(wrapped, encryption_key, mac_key) {
// Split wrapped into its pieces:
actual_mac = wrapped.slice(0, 32);
iv = wrapped.slice(0 + 32, 16);
cipher_text = wrapped.slice(0 + 32 + 16);
// Compute MAC on all inputs:
expected_mac = hmac_sha256(mac_key, encryption_key || iv ||
cipher_text);
// Compare MAC vs value in wrapped:
if (expected_mac != actual_mac) { return Error("MAC does not match"); }
// MAC matches so decrypt:
plain_text = decrypt_aes256_cbc(encryption_key, iv, cipher_text);
return plain_text;
}

Every input to the encryption operation, including the encryption key, must
be included into the HMAC calculation. If you use the same key for both
encryption and MAC that's not required as it's already part of the MAC
process as the key. Using separate keys requires explicitly adding in the
encryption key into the MAC input to ensure that it the correct key prior
to decryption in the unwrap operation. Any additional parts of the wrapped
output (ex: a "version" byte for the algos or padding choices) should also
be included.

The wrap / unwrap above would be used with the encryption and mac keys
derived from the user passphrase to unlock the master_encryption_key and
master_mac_key from pg_control. Then those would be used by the higher
level functions:

pg_kmgr_wrap(plain_text) {
return wrap(plain_text, master_encryption_key, master_mac_key);
}

pg_kmgr_unwrap(wrapped) {
return unwrap(wrapped, master_encryption_key, master_mac_key);
}

Regards,
-- Sehrope Sarkuni
Founder & CEO | JackDB, Inc. | https://www.jackdb.com/

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Kirill Bychik 2020-02-05 13:35:59 WAL usage calculation patch
Previous Message 曾文旌 (义从) 2020-02-05 13:20:11 Re: [Proposal] Global temporary tables