blob: 0b17249c43f7388760668cc6536a20601e568486 [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
Shawn Willden6dde87c2014-12-11 14:08:48 -070017#include <stdio.h>
18
Shawn Willden907c3012014-12-08 15:51:55 -070019#include <openssl/aes.h>
20#include <openssl/rand.h>
21
Shawn Willden63ac0432014-12-29 14:07:08 -070022#include "aes_key.h"
Shawn Willden907c3012014-12-08 15:51:55 -070023#include "aes_operation.h"
24
25namespace keymaster {
26
Shawn Willden63ac0432014-12-29 14:07:08 -070027/**
28 * Abstract base for AES OCB mode operation factories. This class does all of the work to create
29 * OCB mode operations.
30 */
31class AesOcbOperationFactory : public OperationFactory {
32 public:
33 virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_AES, purpose()); }
34
35 virtual Operation* CreateOperation(const Key& key, const Logger& logger,
36 keymaster_error_t* error);
37 virtual const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const;
38
39 virtual keymaster_purpose_t purpose() const = 0;
40};
41
42Operation* AesOcbOperationFactory::CreateOperation(const Key& key, const Logger& logger,
43 keymaster_error_t* error) {
44 *error = KM_ERROR_OK;
45
46 keymaster_block_mode_t block_mode;
47 if (!key.authorizations().GetTagValue(TAG_BLOCK_MODE, &block_mode) ||
48 block_mode != KM_MODE_OCB) {
49 *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
50 return NULL;
51 }
52
53 uint32_t chunk_length;
54 if (!key.authorizations().GetTagValue(TAG_CHUNK_LENGTH, &chunk_length) ||
55 chunk_length > AeadModeOperation::MAX_CHUNK_LENGTH)
56 // TODO(swillden): Create and use a better return code.
57 *error = KM_ERROR_INVALID_ARGUMENT;
58
59 uint32_t tag_length;
60 if (!key.authorizations().GetTagValue(TAG_MAC_LENGTH, &tag_length) ||
61 tag_length > AeadModeOperation::MAX_TAG_LENGTH)
62 // TODO(swillden): Create and use a better return code.
63 *error = KM_ERROR_INVALID_ARGUMENT;
64
65 keymaster_padding_t padding;
66 if (key.authorizations().GetTagValue(TAG_PADDING, &padding) && padding != KM_PAD_NONE)
67 *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
68
69 const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
70 if (!symmetric_key) {
71 *error = KM_ERROR_UNKNOWN_ERROR;
72 return NULL;
73 }
74
75 switch (symmetric_key->key_data_size()) {
76 case 16:
77 case 24:
78 case 32:
79 break;
80 default:
81 *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
82 }
83
84 if (*error != KM_ERROR_OK)
85 return NULL;
86
87 keymaster_blob_t additional_data = {0, 0};
88 symmetric_key->authorizations().GetTagValue(TAG_ASSOCIATED_DATA, &additional_data);
89
90 Operation* op = new AesOcbOperation(purpose(), logger, symmetric_key->key_data(),
91 symmetric_key->key_data_size(), chunk_length, tag_length,
92 additional_data);
93 if (!op)
94 *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
95 return op;
96}
97
98static const keymaster_block_mode_t supported_block_modes[] = {KM_MODE_OCB};
99
100const keymaster_block_mode_t*
101AesOcbOperationFactory::SupportedBlockModes(size_t* block_mode_count) const {
102 *block_mode_count = array_length(supported_block_modes);
103 return supported_block_modes;
104}
105
106/**
107 * Concrete factory for AES OCB mode encryption operations.
108 */
109class AesOcbEncryptionOperationFactory : public AesOcbOperationFactory {
110 keymaster_purpose_t purpose() const { return KM_PURPOSE_ENCRYPT; }
111};
112static OperationFactoryRegistry::Registration<AesOcbEncryptionOperationFactory>
113 encrypt_registration;
114
115/**
116 * Concrete factory for AES OCB mode decryption operations.
117 */
118class AesOcbDecryptionOperationFactory : public AesOcbOperationFactory {
119 keymaster_purpose_t purpose() const { return KM_PURPOSE_DECRYPT; }
120};
121static OperationFactoryRegistry::Registration<AesOcbDecryptionOperationFactory>
122 decrypt_registration;
123
Shawn Willden6dde87c2014-12-11 14:08:48 -0700124keymaster_error_t AesOcbOperation::Initialize(uint8_t* key, size_t key_size, size_t nonce_length,
125 size_t tag_length) {
Shawn Willden63ac0432014-12-29 14:07:08 -0700126 if (tag_length > MAX_TAG_LENGTH || nonce_length > MAX_NONCE_LENGTH)
Shawn Willden6dde87c2014-12-11 14:08:48 -0700127 return KM_ERROR_INVALID_KEY_BLOB;
Shawn Willden907c3012014-12-08 15:51:55 -0700128
Shawn Willden6dde87c2014-12-11 14:08:48 -0700129 if (ae_init(ctx(), key, key_size, nonce_length, tag_length) != AE_SUCCESS) {
130 memset_s(ctx(), 0, ae_ctx_sizeof());
Shawn Willden907c3012014-12-08 15:51:55 -0700131 return KM_ERROR_UNKNOWN_ERROR;
132 }
Shawn Willden907c3012014-12-08 15:51:55 -0700133 return KM_ERROR_OK;
134}
135
Shawn Willden6dde87c2014-12-11 14:08:48 -0700136keymaster_error_t AesOcbOperation::EncryptChunk(const uint8_t* nonce, size_t /* nonce_length */,
137 size_t tag_length,
138 const keymaster_blob_t additional_data,
139 uint8_t* chunk, size_t chunk_size, Buffer* output) {
140 if (!ctx())
141 return KM_ERROR_UNKNOWN_ERROR;
142 uint8_t __attribute__((aligned(16))) tag[MAX_TAG_LENGTH];
Shawn Willden907c3012014-12-08 15:51:55 -0700143
Shawn Willden6dde87c2014-12-11 14:08:48 -0700144 // Encrypt chunk in place.
145 int ae_err = ae_encrypt(ctx(), nonce, chunk, chunk_size, additional_data.data,
146 additional_data.data_length, chunk, tag, AE_FINALIZE);
Shawn Willden907c3012014-12-08 15:51:55 -0700147
Shawn Willden907c3012014-12-08 15:51:55 -0700148 if (ae_err < 0)
149 return KM_ERROR_UNKNOWN_ERROR;
Shawn Willden6dde87c2014-12-11 14:08:48 -0700150 assert(ae_err == (int)buffered_data_length());
Shawn Willden907c3012014-12-08 15:51:55 -0700151
Shawn Willden6dde87c2014-12-11 14:08:48 -0700152 output->write(chunk, buffered_data_length());
153 output->write(tag, tag_length);
Shawn Willden907c3012014-12-08 15:51:55 -0700154
155 return KM_ERROR_OK;
156}
157
Shawn Willden6dde87c2014-12-11 14:08:48 -0700158keymaster_error_t AesOcbOperation::DecryptChunk(const uint8_t* nonce, size_t /* nonce_length */,
159 const uint8_t* tag, size_t /* tag_length */,
160 const keymaster_blob_t additional_data,
161 uint8_t* chunk, size_t chunk_size, Buffer* output) {
162 if (!ctx())
163 return KM_ERROR_UNKNOWN_ERROR;
164
165 // Decrypt chunk in place
166 int ae_err = ae_decrypt(ctx(), nonce, chunk, chunk_size, additional_data.data,
167 additional_data.data_length, chunk, tag, AE_FINALIZE);
168 if (ae_err == AE_INVALID)
169 return KM_ERROR_VERIFICATION_FAILED;
170 else if (ae_err < 0)
171 return KM_ERROR_UNKNOWN_ERROR;
172 assert(ae_err == (int)buffered_data_length());
173 output->write(chunk, chunk_size);
174
175 return KM_ERROR_OK;
Shawn Willden907c3012014-12-08 15:51:55 -0700176}
177
178} // namespace keymaster