1 /** 2 * Transformations of data 3 * 4 * Copyright: 5 * (C) 2013 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.algo_base.transform; 12 13 import memutils.vector; 14 import botan.algo_base.key_spec; 15 import botan.utils.exceptn; 16 import botan.algo_base.symkey; 17 import botan.utils.types; 18 import botan.constants; 19 20 /** 21 * Interface for general transformations on data 22 */ 23 interface Transformation 24 { 25 public: 26 /** 27 * Begin processing a message. 28 * 29 * Params: 30 * nonce = the per message nonce 31 */ 32 final SecureVector!ubyte start(Alloc)(auto const ref RefCounted!(Vector!( ubyte, Alloc ), Alloc) nonce) 33 { 34 return startRaw(nonce.ptr, nonce.length); 35 } 36 37 /** 38 * Begin processing a message. 39 * 40 * Params: 41 * nonce = the per message nonce 42 */ 43 final SecureVector!ubyte start(Alloc)(auto const ref Vector!( ubyte, Alloc ) nonce) 44 { 45 return startRaw(nonce.ptr, nonce.length); 46 } 47 48 /** 49 * Begin processing a message. 50 * 51 * Params: 52 * nonce = a pointer to the per message nonce 53 * nonce_len = the length of the message 54 */ 55 final SecureVector!ubyte start(const(ubyte)* nonce, size_t nonce_len) 56 { 57 return startRaw(nonce, nonce_len); 58 } 59 60 /** 61 * Begin processing a message. 62 */ 63 final SecureVector!ubyte start() 64 { 65 return startRaw(null, 0); 66 } 67 68 /** 69 * Begin processing a message. 70 * 71 * Params: 72 * nonce = the per message nonce 73 * nonce_len = length of nonce 74 */ 75 SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len); 76 77 /** 78 * Process some data. Input must be in size $(D updateGranularity()) ubyte blocks. 79 * 80 * Params: 81 * blocks = in/out paramter which will possibly be resized 82 * offset = an offset into blocks to begin processing 83 */ 84 void update(ref SecureVector!ubyte blocks, size_t offset = 0); 85 86 /** 87 * Complete processing of a message. 88 * 89 * Params: 90 * final_block = in/out parameter which must be at least 91 * $(D minimumFinalSize()) bytes, and will be set to any final output 92 * offset = an offset into final_block to begin processing 93 */ 94 void finish(ref SecureVector!ubyte final_block, size_t offset = 0); 95 96 /** 97 * Returns: The size of the output if this transform is used to process a 98 * message with input_length bytes. Will throw if unable to give a precise 99 * answer. 100 */ 101 size_t outputLength(size_t input_length) const; 102 103 /** 104 * Returns: size of required blocks to update 105 */ 106 size_t updateGranularity() const; 107 108 /** 109 * Returns: required minimium size to $(D finalize()) - may be any length larger than this. 110 */ 111 size_t minimumFinalSize() const; 112 113 /** 114 * Returns: the default size for a nonce 115 */ 116 size_t defaultNonceLength() const; 117 118 /** 119 * Returns: true iff nonce_len is a valid length for the nonce 120 */ 121 bool validNonceLength(size_t nonce_len) const; 122 123 /** 124 * Short name describing the provider of this tranformation. 125 * 126 * Useful in cases where multiple implementations are available (eg, 127 * different implementations of AES). Default "core" is used for the 128 * 'standard' implementation included in the library. 129 */ 130 string provider() const; 131 132 @property string name() const; 133 134 void clear(); 135 } 136 137 class KeyedTransform : Transformation 138 { 139 public: 140 /** 141 * Returns: object describing limits on key size 142 */ 143 abstract KeyLengthSpecification keySpec() const; 144 145 /** 146 * Check whether a given key length is valid for this algorithm. 147 * 148 * Params: 149 * length = the key length to be checked. 150 * 151 * Returns: true if the key length is valid. 152 */ 153 final bool validKeylength(size_t length) const 154 { 155 return keySpec().validKeylength(length); 156 } 157 158 159 160 /** 161 * Set the symmetric key of this transform 162 * 163 * Params: 164 * key = contains the key material 165 * length = size in bytes of key param 166 */ 167 final void setKey(const(ubyte)* key, size_t length) 168 { 169 if (!validKeylength(length)) 170 throw new InvalidKeyLength(name, length); 171 keySchedule(key, length); 172 } 173 174 /// ditto 175 final void setKey(Alloc)(in RefCounted!(Vector!( ubyte, Alloc ), Alloc) key) 176 { 177 setKey(key.ptr, key.length); 178 } 179 180 /// ditto 181 final void setKey(Alloc)(const ref Vector!( ubyte, Alloc ) key) 182 { 183 setKey(key.ptr, key.length); 184 } 185 186 /// ditto 187 final void setKey(in SymmetricKey key) 188 { 189 setKey(key.ptr, key.length); 190 } 191 192 193 protected: 194 195 abstract void keySchedule(const(ubyte)* key, size_t length); 196 } 197 198 static if (BOTAN_TEST): 199 200 import botan.test; 201 import botan.codec.hex; 202 import core.atomic; 203 import memutils.hashmap; 204 205 shared size_t total_tests; 206 207 Transformation getTransform(string algo) 208 { 209 throw new Exception("Unknown transform " ~ algo); 210 } 211 212 SecureVector!ubyte transformTest(string algo, 213 in SecureVector!ubyte nonce, 214 in SecureVector!ubyte /*key*/, 215 in SecureVector!ubyte input) 216 { 217 Unique!Transformation transform = getTransform(algo); 218 219 //transform.setKey(key); 220 transform.start(nonce); 221 222 SecureVector!ubyte output = input.dup; 223 transform.update(output, 0); 224 225 return output; 226 } 227 228 static if (BOTAN_HAS_TESTS && !SKIP_TRANSFORM_TEST) unittest 229 { 230 logDebug("Testing transform.d ..."); 231 File vec = File("test_data/transform.vec", "r"); 232 size_t fails = runTests(vec, "Transform", "Output", true, 233 (ref HashMap!(string, string) m) { 234 atomicOp!"+="(total_tests, 1); 235 return hexEncode(transformTest(m["Transform"], 236 hexDecodeLocked(m["Nonce"]), 237 hexDecodeLocked(m["Key"]), 238 hexDecodeLocked(m["Input"]))); 239 }); 240 241 testReport("transform", total_tests, fails); 242 }