Botan 3.0.0
Crypto and TLS for C&
commoncrypto_utils.cpp
Go to the documentation of this file.
1/*
2* Cipher Modes via CommonCrypto
3* (C) 2018 Jose Pereira
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/commoncrypto.h>
9#include <botan/internal/commoncrypto_utils.h>
10#include <botan/cipher_mode.h>
11#include <botan/internal/parsing.h>
12#include <botan/internal/scan_name.h>
13#include <botan/internal/fmt.h>
14
15namespace Botan {
16
18 Exception(what),
19 m_rc(0) {}
20
21CommonCrypto_Error::CommonCrypto_Error(std::string_view what, int32_t status) :
22 Exception(fmt("CommonCrypto op {} failed with err {} ({})",
23 what, status, ccryptorstatus_to_string(status))),
24 m_rc(status) {}
25
26std::string CommonCrypto_Error::ccryptorstatus_to_string(CCCryptorStatus status)
27 {
28 switch(status)
29 {
30 case kCCSuccess:
31 return "Success";
32 case kCCParamError:
33 return "ParamError";
34 case kCCBufferTooSmall:
35 return "BufferTooSmall";
36 case kCCMemoryFailure:
37 return "MemoryFailure";
38 case kCCAlignmentError:
39 return "AlignmentError";
40 case kCCDecodeError:
41 return "DecodeError";
42 case kCCUnimplemented:
43 return "Unimplemented";
44 case kCCOverflow:
45 return "Overflow";
46 case kCCRNGFailure:
47 return "RNGFailure";
48 case kCCUnspecifiedError:
49 return "UnspecifiedError";
50 case kCCCallSequenceError:
51 return "CallSequenceError";
52 case kCCKeySizeError:
53 return "KeySizeError";
54 default:
55 return "Unknown";
56 }
57 };
58
59
61 {
63
64 if(algo_name.compare(0, 3, "AES") == 0)
65 {
66 opts.algo = kCCAlgorithmAES;
67 opts.block_size = kCCBlockSizeAES128;
68 if(algo_name == "AES-128")
69 {
70 opts.key_spec = Key_Length_Specification(kCCKeySizeAES128);
71 }
72 else if(algo_name == "AES-192")
73 {
74 opts.key_spec = Key_Length_Specification(kCCKeySizeAES192);
75 }
76 else if(algo_name == "AES-256")
77 {
78 opts.key_spec = Key_Length_Specification(kCCKeySizeAES256);
79 }
80 else
81 {
82 throw CommonCrypto_Error("Unknown AES algorithm");
83 }
84 }
85 else if(algo_name == "DES")
86 {
87 opts.algo = kCCAlgorithmDES;
88 opts.block_size = kCCBlockSizeDES;
89 opts.key_spec = Key_Length_Specification(kCCKeySizeDES);
90 }
91 else if(algo_name == "TripleDES")
92 {
93 opts.algo = kCCAlgorithm3DES;
94 opts.block_size = kCCBlockSize3DES;
95 opts.key_spec = Key_Length_Specification(16, kCCKeySize3DES, 8);
96 }
97 else if(algo_name == "Blowfish")
98 {
99 opts.algo = kCCAlgorithmBlowfish;
100 opts.block_size = kCCBlockSizeBlowfish;
101 opts.key_spec = Key_Length_Specification(1, kCCKeySizeMaxBlowfish, 1);
102 }
103 else if(algo_name == "CAST-128")
104 {
105 opts.algo = kCCAlgorithmCAST;
106 opts.block_size = kCCBlockSizeCAST;
107 // Botan's base implementation of CAST does not support shorter keys
108 // so we limit its minimum key size to 11 here.
109 opts.key_spec = Key_Length_Specification(11, kCCKeySizeMaxCAST, 1);
110 }
111 else
112 {
113 throw CommonCrypto_Error("Unsupported cipher");
114 }
115
116 return opts;
117 }
118
119
121 {
122 SCAN_Name spec(algo);
123
124 std::string algo_name = spec.algo_name();
125 std::string cipher_mode = spec.cipher_mode();
126 std::string cipher_mode_padding = spec.cipher_mode_pad();
127
129
130 //TODO add CFB and XTS support
131 if(cipher_mode.empty() || cipher_mode == "ECB")
132 {
133 opts.mode = kCCModeECB;
134 }
135 else if(cipher_mode == "CBC")
136 {
137 opts.mode = kCCModeCBC;
138 }
139 else if(cipher_mode == "CTR")
140 {
141 opts.mode = kCCModeCTR;
142 }
143 else if(cipher_mode == "OFB")
144 {
145 opts.mode = kCCModeOFB;
146 }
147 else
148 {
149 throw CommonCrypto_Error("Unsupported cipher mode!");
150 }
151
152 if(cipher_mode_padding == "NoPadding")
153 {
154 opts.padding = ccNoPadding;
155 }
156 /*
157 else if(cipher_mode_padding.empty() || cipher_mode_padding == "PKCS7")
158 {
159 opts.padding = ccPKCS7Padding;
160 }
161 */
162 else
163 {
164 throw CommonCrypto_Error("Unsupported cipher mode padding!");
165 }
166
167 return opts;
168 }
169
170
171void commoncrypto_adjust_key_size(const uint8_t key[], size_t length,
172 const CommonCryptor_Opts& opts,
173 secure_vector<uint8_t>& full_key)
174 {
175 if(opts.algo == kCCAlgorithmBlowfish && length < 8)
176 {
177 size_t repeat;
178 switch(length)
179 {
180 case 1:
181 repeat = 8;
182 break;
183 case 2:
184 repeat = 4;
185 break;
186 case 3:
187 repeat = 3;
188 break;
189 default:
190 repeat = 2;
191 break;
192 }
193
194 full_key.resize(length * repeat);
195 for(size_t i = 0; i < repeat; i++)
196 {
197 copy_mem(full_key.data() + i * length, key, length);
198 }
199 }
200 else if(opts.algo == kCCAlgorithm3DES && length == 16)
201 {
202 full_key += std::make_pair(key, 8);
203 }
204 }
205}
CommonCrypto_Error(std::string_view what)
const std::string algo_name() const
Definition: scan_name.h:45
std::string cipher_mode_pad() const
Definition: scan_name.h:95
std::string cipher_mode() const
Definition: scan_name.h:89
Definition: alg_id.cpp:12
std::string fmt(std::string_view format, const T &... args)
Definition: fmt.h:60
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:126
int32_t CCCryptorStatus
Definition: commoncrypto.h:24
void commoncrypto_adjust_key_size(const uint8_t key[], size_t length, const CommonCryptor_Opts &opts, secure_vector< uint8_t > &full_key)
CommonCryptor_Opts commoncrypto_opts_from_algo(std::string_view algo)
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:64
CommonCryptor_Opts commoncrypto_opts_from_algo_name(std::string_view algo_name)
Key_Length_Specification key_spec