All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.crypto.tink.hybrid.internal.HpkeContext Maven / Gradle / Ivy

// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////

package com.google.crypto.tink.hybrid.internal;

import com.google.crypto.tink.AccessesPartialKey;
import com.google.crypto.tink.hybrid.HpkePublicKey;
import com.google.crypto.tink.internal.BigIntegerEncoding;
import com.google.crypto.tink.subtle.Bytes;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;

/**
 * Hybrid Public Key Encryption (HPKE) context for either a sender or a recipient.
 *
 * 

https://www.rfc-editor.org/rfc/rfc9180.html#name-creating-the-encryption-con */ @ThreadSafe public final class HpkeContext { private static final byte[] EMPTY_IKM = new byte[0]; private final HpkeAead aead; private final BigInteger maxSequenceNumber; private final byte[] key; private final byte[] baseNonce; private final byte[] encapsulatedKey; @GuardedBy("this") private BigInteger sequenceNumber; private HpkeContext( byte[] encapsulatedKey, byte[] key, byte[] baseNonce, BigInteger maxSequenceNumber, HpkeAead aead) { this.encapsulatedKey = encapsulatedKey; this.key = key; this.baseNonce = baseNonce; this.sequenceNumber = BigInteger.ZERO; this.maxSequenceNumber = maxSequenceNumber; this.aead = aead; } /** Helper function factored out to facilitate unit testing. */ static HpkeContext createContext( byte[] mode, byte[] encapsulatedKey, byte[] sharedSecret, HpkeKem kem, HpkeKdf kdf, HpkeAead aead, byte[] info) throws GeneralSecurityException { byte[] suiteId = HpkeUtil.hpkeSuiteId(kem.getKemId(), kdf.getKdfId(), aead.getAeadId()); byte[] pskIdHash = kdf.labeledExtract(HpkeUtil.EMPTY_SALT, EMPTY_IKM, "psk_id_hash", suiteId); byte[] infoHash = kdf.labeledExtract(HpkeUtil.EMPTY_SALT, info, "info_hash", suiteId); byte[] keyScheduleContext = Bytes.concat(mode, pskIdHash, infoHash); byte[] secret = kdf.labeledExtract(sharedSecret, EMPTY_IKM, "secret", suiteId); byte[] key = kdf.labeledExpand(secret, keyScheduleContext, "key", suiteId, aead.getKeyLength()); byte[] baseNonce = kdf.labeledExpand(secret, keyScheduleContext, "base_nonce", suiteId, aead.getNonceLength()); BigInteger maxSeqNo = maxSequenceNumber(aead.getNonceLength()); return new HpkeContext(encapsulatedKey, key, baseNonce, maxSeqNo, aead); } /** * Creates HPKE sender context according to KeySchedule() defined in * https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1-9. * * @param recipientPublicKey recipient's public key (pkR) * @param kem key encapsulation mechanism primitive * @param kdf key derivation function primitive * @param aead authenticated encryption with associated data primitive * @param info application-specific information parameter to influence key generation */ static HpkeContext createSenderContext( byte[] recipientPublicKey, HpkeKem kem, HpkeKdf kdf, HpkeAead aead, byte[] info) throws GeneralSecurityException { HpkeKemEncapOutput encapOutput = kem.encapsulate(recipientPublicKey); byte[] encapsulatedKey = encapOutput.getEncapsulatedKey(); byte[] sharedSecret = encapOutput.getSharedSecret(); return createContext(HpkeUtil.BASE_MODE, encapsulatedKey, sharedSecret, kem, kdf, aead, info); } /** * Creates HPKE sender context with authentication according to KeySchedule() defined in * https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1.3. * * @param recipientPublicKey recipient's public key (pkR) * @param kem key encapsulation mechanism primitive * @param kdf key derivation function primitive * @param aead authenticated encryption with associated data primitive * @param info application-specific information parameter to influence key generation * @param senderPrivateKey sender's private key (skS) */ @AccessesPartialKey public static HpkeContext createAuthSenderContext( HpkePublicKey recipientPublicKey, HpkeKem kem, HpkeKdf kdf, HpkeAead aead, byte[] info, HpkeKemPrivateKey senderPrivateKey) throws GeneralSecurityException { HpkeKemEncapOutput encapOutput = kem.authEncapsulate(recipientPublicKey.getPublicKeyBytes().toByteArray(), senderPrivateKey); byte[] encapsulatedKey = encapOutput.getEncapsulatedKey(); byte[] sharedSecret = encapOutput.getSharedSecret(); return createContext(HpkeUtil.AUTH_MODE, encapsulatedKey, sharedSecret, kem, kdf, aead, info); } /** * Creates HPKE sender recipient context according to KeySchedule() defined in * https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1-9. * * @param encapsulatedKey encapsulated key (enc) * @param recipientPrivateKey recipient's private key (skR) * @param kem key encapsulation mechanism primitive * @param kdf key derivation function primitive * @param aead authenticated encryption with associated data primitive * @param info application-specific information parameter to influence key generation */ public static HpkeContext createRecipientContext( byte[] encapsulatedKey, HpkeKemPrivateKey recipientPrivateKey, HpkeKem kem, HpkeKdf kdf, HpkeAead aead, byte[] info) throws GeneralSecurityException { byte[] sharedSecret = kem.decapsulate(encapsulatedKey, recipientPrivateKey); return createContext(HpkeUtil.BASE_MODE, encapsulatedKey, sharedSecret, kem, kdf, aead, info); } /** * Creates HPKE recipient context with authentication according to KeySchedule() defined in * https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1.3. * * @param encapsulatedKey encapsulated key (enc) * @param recipientPrivateKey recipient's private key (skR) * @param kem key encapsulation mechanism primitive * @param kdf key derivation function primitive * @param aead authenticated encryption with associated data primitive * @param info application-specific information parameter to influence key generation * @param senderPublicKey sender's public key (pkS) */ @AccessesPartialKey public static HpkeContext createAuthRecipientContext( byte[] encapsulatedKey, HpkeKemPrivateKey recipientPrivateKey, HpkeKem kem, HpkeKdf kdf, HpkeAead aead, byte[] info, HpkePublicKey senderPublicKey) throws GeneralSecurityException { byte[] sharedSecret = kem.authDecapsulate( encapsulatedKey, recipientPrivateKey, senderPublicKey.getPublicKeyBytes().toByteArray()); return createContext(HpkeUtil.AUTH_MODE, encapsulatedKey, sharedSecret, kem, kdf, aead, info); } private static BigInteger maxSequenceNumber(int nonceLength) { return BigInteger.ONE.shiftLeft(8 * nonceLength).subtract(BigInteger.ONE); } @GuardedBy("this") private void incrementSequenceNumber() throws GeneralSecurityException { if (sequenceNumber.compareTo(maxSequenceNumber) >= 0) { throw new GeneralSecurityException("message limit reached"); } sequenceNumber = sequenceNumber.add(BigInteger.ONE); } /** ComputeNonce() from https://www.rfc-editor.org/rfc/rfc9180.html#section-5.2-11. */ @GuardedBy("this") private byte[] computeNonce() throws GeneralSecurityException { return Bytes.xor( baseNonce, BigIntegerEncoding.toBigEndianBytesOfFixedLength(sequenceNumber, aead.getNonceLength())); } /** Returns the next nonce to use for seal/open. Also, increments the sequence number. */ private synchronized byte[] computeNonceAndIncrementSequenceNumber() throws GeneralSecurityException { byte[] nonce = computeNonce(); incrementSequenceNumber(); return nonce; } byte[] getKey() { return key; } byte[] getBaseNonce() { return baseNonce; } public byte[] getEncapsulatedKey() { return encapsulatedKey; } /** * Performs AEAD encryption of {@code plaintext} with {@code associatedData} according to * ContextS.Seal() defined in https://www.rfc-editor.org/rfc/rfc9180.html#section-5.2-8. * * @return ciphertext */ public byte[] seal(byte[] plaintext, byte[] associatedData) throws GeneralSecurityException { byte[] nonce = computeNonceAndIncrementSequenceNumber(); return aead.seal(key, nonce, plaintext, associatedData); } byte[] seal(byte[] plaintext, int ciphertextOffset, byte[] associatedData) throws GeneralSecurityException { byte[] nonce = computeNonceAndIncrementSequenceNumber(); return aead.seal(key, nonce, plaintext, ciphertextOffset, associatedData); } /** * Performs AEAD decryption of {@code ciphertext} with {@code associatedData} according to * ContextR.Open() defined in https://www.rfc-editor.org/rfc/rfc9180.html#section-5.2-10. * * @return plaintext */ public byte[] open(byte[] ciphertext, byte[] associatedData) throws GeneralSecurityException { return open(ciphertext, /* ciphertextOffset = */ 0, associatedData); } byte[] open(byte[] ciphertext, int ciphertextOffset, byte[] associatedData) throws GeneralSecurityException { byte[] nonce = computeNonceAndIncrementSequenceNumber(); return aead.open(key, nonce, ciphertext, ciphertextOffset, associatedData); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy