blob: fb129933613631a002eea57ae7f9234f7fd082d6 [file] [log] [blame]
// Copyright 2019 Google Inc.
//
// 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.
//
///////////////////////////////////////////////////////////////////////////////
#include "tink/subtle/aes_gcm_hkdf_streaming.h"
#include <string>
#include "tink/subtle/aes_gcm_hkdf_stream_segment_decrypter.h"
#include "tink/subtle/aes_gcm_hkdf_stream_segment_encrypter.h"
#include "tink/subtle/common_enums.h"
#include "tink/subtle/hkdf.h"
#include "tink/subtle/random.h"
#include "tink/subtle/stream_segment_decrypter.h"
#include "tink/subtle/stream_segment_encrypter.h"
#include "tink/util/errors.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
namespace crypto {
namespace tink {
namespace subtle {
using crypto::tink::util::Status;
using crypto::tink::util::StatusOr;
namespace {
Status Validate(absl::string_view ikm,
HashType hkdf_hash,
int derived_key_size,
int ciphertext_segment_size,
int ciphertext_offset) {
if (!(hkdf_hash == SHA1 || hkdf_hash == SHA256 || hkdf_hash == SHA512)) {
return Status(util::error::INVALID_ARGUMENT, "unsupported hkdf_hash");
}
if (ikm.size() < 16 || ikm.size() < derived_key_size) {
return Status(util::error::INVALID_ARGUMENT, "ikm too small");
}
if (derived_key_size != 16 && derived_key_size != 32) {
return util::Status(util::error::INVALID_ARGUMENT,
"derived_key_size must be 16 or 32");
}
if (ciphertext_offset < 0) {
return util::Status(util::error::INVALID_ARGUMENT,
"ciphertext_offset must be non-negative");
}
if (ciphertext_segment_size <=
ciphertext_offset + derived_key_size +
AesGcmHkdfStreamSegmentEncrypter::kTagSizeInBytes) {
return util::Status(util::error::INVALID_ARGUMENT,
"ciphertext_segment_size too small");
}
return util::OkStatus();
}
} // namespace
StatusOr<std::unique_ptr<AesGcmHkdfStreaming>>
AesGcmHkdfStreaming::New(absl::string_view ikm,
HashType hkdf_hash,
int derived_key_size,
int ciphertext_segment_size,
int ciphertext_offset) {
auto status = Validate(ikm, hkdf_hash, derived_key_size,
ciphertext_segment_size, ciphertext_offset);
if (!status.ok()) return status;
std::unique_ptr<AesGcmHkdfStreaming>
streaming_aead(new AesGcmHkdfStreaming());
streaming_aead->ikm_ = std::string(ikm);
streaming_aead->hkdf_hash_ = hkdf_hash;
streaming_aead->derived_key_size_ = derived_key_size;
streaming_aead->ciphertext_segment_size_ = ciphertext_segment_size;
streaming_aead->ciphertext_offset_ = ciphertext_offset;
return std::move(streaming_aead);
}
StatusOr<std::unique_ptr<StreamSegmentEncrypter>>
AesGcmHkdfStreaming::NewSegmentEncrypter(
absl::string_view associated_data) const {
AesGcmHkdfStreamSegmentEncrypter::Params params;
params.salt = Random::GetRandomBytes(derived_key_size_);
auto hkdf_result = Hkdf::ComputeHkdf(
hkdf_hash_, ikm_, params.salt, associated_data,
derived_key_size_);
if (!hkdf_result.ok()) return hkdf_result.status();
params.key_value = hkdf_result.ValueOrDie();
params.ciphertext_offset = ciphertext_offset_;
params.ciphertext_segment_size = ciphertext_segment_size_;
return AesGcmHkdfStreamSegmentEncrypter::New(params);
}
StatusOr<std::unique_ptr<StreamSegmentDecrypter>>
AesGcmHkdfStreaming::NewSegmentDecrypter(
absl::string_view associated_data) const {
AesGcmHkdfStreamSegmentDecrypter::Params params;
params.ikm = ikm_;
params.hkdf_hash = hkdf_hash_;
params.derived_key_size = derived_key_size_;
params.ciphertext_offset = ciphertext_offset_;
params.ciphertext_segment_size = ciphertext_segment_size_;
params.associated_data = std::string(associated_data);
return AesGcmHkdfStreamSegmentDecrypter::New(params);
}
} // namespace subtle
} // namespace tink
} // namespace crypto