blob: 346c857f3f22daa2a546eaee38880279318ce826 [file] [log] [blame]
Shawn Willden907c3012014-12-08 15:51:55 -07001/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <openssl/aes.h>
18#include <openssl/rand.h>
19
20#include "aes_operation.h"
21
22namespace keymaster {
23
24keymaster_error_t AesOcbEncryptOperation::Begin() {
25 chunk_.reset(new uint8_t[chunk_length_]);
26 if (!chunk_.get())
27 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
28
29 if (!RAND_bytes(nonce_, NONCE_LENGTH))
30 return KM_ERROR_UNKNOWN_ERROR;
31
32 if (ae_init(ctx_.get(), key_, key_size_, array_size(nonce_), tag_length_) != AE_SUCCESS) {
33 memset_s(ctx_.get(), 0, ae_ctx_sizeof());
34 return KM_ERROR_UNKNOWN_ERROR;
35 }
36
37 return KM_ERROR_OK;
38}
39
40keymaster_error_t AesOcbEncryptOperation::Update(const Buffer& input, Buffer* output,
41 size_t* input_consumed) {
42 const uint8_t* plaintext = input.peek_read();
43 const uint8_t* plaintext_end = plaintext + input.available_read();
44
45 while (plaintext + chunk_unfilled_space() < plaintext_end) {
46 size_t to_process = chunk_unfilled_space();
47 memcpy(chunk_.get() + chunk_offset_, plaintext, to_process);
48 chunk_offset_ += to_process;
49 assert(chunk_offset_ == chunk_length_);
50
51 keymaster_error_t error = ProcessChunk(output);
52 if (error != KM_ERROR_OK)
53 return error;
54 plaintext += to_process;
55 }
56
57 // Copy remaining data into chunk_.
58 assert(plaintext_end - plaintext < chunk_unfilled_space());
59 memcpy(chunk_.get() + chunk_offset_, plaintext, plaintext_end - plaintext);
60 chunk_offset_ += (plaintext_end - plaintext);
61
62 *input_consumed = input.available_read();
63 return KM_ERROR_OK;
64}
65
66keymaster_error_t AesOcbEncryptOperation::Finish(const Buffer& /* signature */, Buffer* output) {
67 keymaster_error_t error = KM_ERROR_OK;
68 if (chunk_offset_ > 0)
69 error = ProcessChunk(output);
70 return error;
71}
72
73keymaster_error_t AesOcbEncryptOperation::ProcessChunk(Buffer* output) {
74 if (!nonce_written_) {
75 if (!output->reserve(NONCE_LENGTH + chunk_length_ + tag_length_))
76 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
77 output->write(nonce_, NONCE_LENGTH);
78 nonce_written_ = true;
79 } else {
80 IncrementNonce();
81 }
82
83 if (!output->reserve(output->available_read() + chunk_offset_ + tag_length_))
84 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
85
86 int ae_err = ae_encrypt(ctx_.get(), nonce_, chunk_.get(), chunk_offset_, additional_data_.data,
87 additional_data_.data_length, output->peek_write(), tag_, AE_FINALIZE);
88 if (ae_err < 0)
89 return KM_ERROR_UNKNOWN_ERROR;
90 output->advance_write(chunk_offset_);
91 chunk_offset_ = 0;
92
93 // Output the tag.
94 output->write(tag_, tag_length_);
95
96 return KM_ERROR_OK;
97}
98
99void AesOcbEncryptOperation::IncrementNonce() {
100 for (int i = NONCE_LENGTH - 1; i > 0; --i)
101 if (++nonce_[i])
102 break;
103}
104
105} // namespace keymaster