Botan
1.11.15
|
00001 /* 00002 * Load/Store Operators 00003 * (C) 1999-2007 Jack Lloyd 00004 * 2007 Yves Jerschow 00005 * 00006 * Botan is released under the Simplified BSD License (see license.txt) 00007 */ 00008 00009 #ifndef BOTAN_LOAD_STORE_H__ 00010 #define BOTAN_LOAD_STORE_H__ 00011 00012 #include <botan/types.h> 00013 #include <botan/bswap.h> 00014 #include <botan/get_byte.h> 00015 #include <botan/mem_ops.h> 00016 #include <vector> 00017 00018 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00019 00020 #if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) 00021 00022 #define BOTAN_ENDIAN_N2B(x) (x) 00023 #define BOTAN_ENDIAN_B2N(x) (x) 00024 00025 #define BOTAN_ENDIAN_N2L(x) reverse_bytes(x) 00026 #define BOTAN_ENDIAN_L2N(x) reverse_bytes(x) 00027 00028 #elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) 00029 00030 #define BOTAN_ENDIAN_N2L(x) (x) 00031 #define BOTAN_ENDIAN_L2N(x) (x) 00032 00033 #define BOTAN_ENDIAN_N2B(x) reverse_bytes(x) 00034 #define BOTAN_ENDIAN_B2N(x) reverse_bytes(x) 00035 00036 #endif 00037 00038 #endif 00039 00040 namespace Botan { 00041 00042 /** 00043 * Make a u16bit from two bytes 00044 * @param i0 the first byte 00045 * @param i1 the second byte 00046 * @return i0 || i1 00047 */ 00048 inline u16bit make_u16bit(byte i0, byte i1) 00049 { 00050 return ((static_cast<u16bit>(i0) << 8) | i1); 00051 } 00052 00053 /** 00054 * Make a u32bit from four bytes 00055 * @param i0 the first byte 00056 * @param i1 the second byte 00057 * @param i2 the third byte 00058 * @param i3 the fourth byte 00059 * @return i0 || i1 || i2 || i3 00060 */ 00061 inline u32bit make_u32bit(byte i0, byte i1, byte i2, byte i3) 00062 { 00063 return ((static_cast<u32bit>(i0) << 24) | 00064 (static_cast<u32bit>(i1) << 16) | 00065 (static_cast<u32bit>(i2) << 8) | 00066 (static_cast<u32bit>(i3))); 00067 } 00068 00069 /** 00070 * Make a u32bit from eight bytes 00071 * @param i0 the first byte 00072 * @param i1 the second byte 00073 * @param i2 the third byte 00074 * @param i3 the fourth byte 00075 * @param i4 the fifth byte 00076 * @param i5 the sixth byte 00077 * @param i6 the seventh byte 00078 * @param i7 the eighth byte 00079 * @return i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7 00080 */ 00081 inline u64bit make_u64bit(byte i0, byte i1, byte i2, byte i3, 00082 byte i4, byte i5, byte i6, byte i7) 00083 { 00084 return ((static_cast<u64bit>(i0) << 56) | 00085 (static_cast<u64bit>(i1) << 48) | 00086 (static_cast<u64bit>(i2) << 40) | 00087 (static_cast<u64bit>(i3) << 32) | 00088 (static_cast<u64bit>(i4) << 24) | 00089 (static_cast<u64bit>(i5) << 16) | 00090 (static_cast<u64bit>(i6) << 8) | 00091 (static_cast<u64bit>(i7))); 00092 } 00093 00094 /** 00095 * Load a big-endian word 00096 * @param in a pointer to some bytes 00097 * @param off an offset into the array 00098 * @return off'th T of in, as a big-endian value 00099 */ 00100 template<typename T> 00101 inline T load_be(const byte in[], size_t off) 00102 { 00103 in += off * sizeof(T); 00104 T out = 0; 00105 for(size_t i = 0; i != sizeof(T); ++i) 00106 out = (out << 8) | in[i]; 00107 return out; 00108 } 00109 00110 /** 00111 * Load a little-endian word 00112 * @param in a pointer to some bytes 00113 * @param off an offset into the array 00114 * @return off'th T of in, as a litte-endian value 00115 */ 00116 template<typename T> 00117 inline T load_le(const byte in[], size_t off) 00118 { 00119 in += off * sizeof(T); 00120 T out = 0; 00121 for(size_t i = 0; i != sizeof(T); ++i) 00122 out = (out << 8) | in[sizeof(T)-1-i]; 00123 return out; 00124 } 00125 00126 /** 00127 * Load a big-endian u16bit 00128 * @param in a pointer to some bytes 00129 * @param off an offset into the array 00130 * @return off'th u16bit of in, as a big-endian value 00131 */ 00132 template<> 00133 inline u16bit load_be<u16bit>(const byte in[], size_t off) 00134 { 00135 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00136 return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u16bit*>(in) + off)); 00137 #else 00138 in += off * sizeof(u16bit); 00139 return make_u16bit(in[0], in[1]); 00140 #endif 00141 } 00142 00143 /** 00144 * Load a little-endian u16bit 00145 * @param in a pointer to some bytes 00146 * @param off an offset into the array 00147 * @return off'th u16bit of in, as a little-endian value 00148 */ 00149 template<> 00150 inline u16bit load_le<u16bit>(const byte in[], size_t off) 00151 { 00152 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00153 return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u16bit*>(in) + off)); 00154 #else 00155 in += off * sizeof(u16bit); 00156 return make_u16bit(in[1], in[0]); 00157 #endif 00158 } 00159 00160 /** 00161 * Load a big-endian u32bit 00162 * @param in a pointer to some bytes 00163 * @param off an offset into the array 00164 * @return off'th u32bit of in, as a big-endian value 00165 */ 00166 template<> 00167 inline u32bit load_be<u32bit>(const byte in[], size_t off) 00168 { 00169 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00170 return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u32bit*>(in) + off)); 00171 #else 00172 in += off * sizeof(u32bit); 00173 return make_u32bit(in[0], in[1], in[2], in[3]); 00174 #endif 00175 } 00176 00177 /** 00178 * Load a little-endian u32bit 00179 * @param in a pointer to some bytes 00180 * @param off an offset into the array 00181 * @return off'th u32bit of in, as a little-endian value 00182 */ 00183 template<> 00184 inline u32bit load_le<u32bit>(const byte in[], size_t off) 00185 { 00186 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00187 return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u32bit*>(in) + off)); 00188 #else 00189 in += off * sizeof(u32bit); 00190 return make_u32bit(in[3], in[2], in[1], in[0]); 00191 #endif 00192 } 00193 00194 /** 00195 * Load a big-endian u64bit 00196 * @param in a pointer to some bytes 00197 * @param off an offset into the array 00198 * @return off'th u64bit of in, as a big-endian value 00199 */ 00200 template<> 00201 inline u64bit load_be<u64bit>(const byte in[], size_t off) 00202 { 00203 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00204 return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u64bit*>(in) + off)); 00205 #else 00206 in += off * sizeof(u64bit); 00207 return make_u64bit(in[0], in[1], in[2], in[3], 00208 in[4], in[5], in[6], in[7]); 00209 #endif 00210 } 00211 00212 /** 00213 * Load a little-endian u64bit 00214 * @param in a pointer to some bytes 00215 * @param off an offset into the array 00216 * @return off'th u64bit of in, as a little-endian value 00217 */ 00218 template<> 00219 inline u64bit load_le<u64bit>(const byte in[], size_t off) 00220 { 00221 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00222 return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u64bit*>(in) + off)); 00223 #else 00224 in += off * sizeof(u64bit); 00225 return make_u64bit(in[7], in[6], in[5], in[4], 00226 in[3], in[2], in[1], in[0]); 00227 #endif 00228 } 00229 00230 /** 00231 * Load two little-endian words 00232 * @param in a pointer to some bytes 00233 * @param x0 where the first word will be written 00234 * @param x1 where the second word will be written 00235 */ 00236 template<typename T> 00237 inline void load_le(const byte in[], T& x0, T& x1) 00238 { 00239 x0 = load_le<T>(in, 0); 00240 x1 = load_le<T>(in, 1); 00241 } 00242 00243 /** 00244 * Load four little-endian words 00245 * @param in a pointer to some bytes 00246 * @param x0 where the first word will be written 00247 * @param x1 where the second word will be written 00248 * @param x2 where the third word will be written 00249 * @param x3 where the fourth word will be written 00250 */ 00251 template<typename T> 00252 inline void load_le(const byte in[], 00253 T& x0, T& x1, T& x2, T& x3) 00254 { 00255 x0 = load_le<T>(in, 0); 00256 x1 = load_le<T>(in, 1); 00257 x2 = load_le<T>(in, 2); 00258 x3 = load_le<T>(in, 3); 00259 } 00260 00261 /** 00262 * Load eight little-endian words 00263 * @param in a pointer to some bytes 00264 * @param x0 where the first word will be written 00265 * @param x1 where the second word will be written 00266 * @param x2 where the third word will be written 00267 * @param x3 where the fourth word will be written 00268 * @param x4 where the fifth word will be written 00269 * @param x5 where the sixth word will be written 00270 * @param x6 where the seventh word will be written 00271 * @param x7 where the eighth word will be written 00272 */ 00273 template<typename T> 00274 inline void load_le(const byte in[], 00275 T& x0, T& x1, T& x2, T& x3, 00276 T& x4, T& x5, T& x6, T& x7) 00277 { 00278 x0 = load_le<T>(in, 0); 00279 x1 = load_le<T>(in, 1); 00280 x2 = load_le<T>(in, 2); 00281 x3 = load_le<T>(in, 3); 00282 x4 = load_le<T>(in, 4); 00283 x5 = load_le<T>(in, 5); 00284 x6 = load_le<T>(in, 6); 00285 x7 = load_le<T>(in, 7); 00286 } 00287 00288 /** 00289 * Load a variable number of little-endian words 00290 * @param out the output array of words 00291 * @param in the input array of bytes 00292 * @param count how many words are in in 00293 */ 00294 template<typename T> 00295 inline void load_le(T out[], 00296 const byte in[], 00297 size_t count) 00298 { 00299 #if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) 00300 std::memcpy(out, in, sizeof(T)*count); 00301 00302 #if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) 00303 const size_t blocks = count - (count % 4); 00304 const size_t left = count - blocks; 00305 00306 for(size_t i = 0; i != blocks; i += 4) 00307 bswap_4(out + i); 00308 00309 for(size_t i = 0; i != left; ++i) 00310 out[blocks+i] = reverse_bytes(out[blocks+i]); 00311 #endif 00312 00313 #else 00314 for(size_t i = 0; i != count; ++i) 00315 out[i] = load_le<T>(in, i); 00316 #endif 00317 } 00318 00319 /** 00320 * Load two big-endian words 00321 * @param in a pointer to some bytes 00322 * @param x0 where the first word will be written 00323 * @param x1 where the second word will be written 00324 */ 00325 template<typename T> 00326 inline void load_be(const byte in[], T& x0, T& x1) 00327 { 00328 x0 = load_be<T>(in, 0); 00329 x1 = load_be<T>(in, 1); 00330 } 00331 00332 /** 00333 * Load four big-endian words 00334 * @param in a pointer to some bytes 00335 * @param x0 where the first word will be written 00336 * @param x1 where the second word will be written 00337 * @param x2 where the third word will be written 00338 * @param x3 where the fourth word will be written 00339 */ 00340 template<typename T> 00341 inline void load_be(const byte in[], 00342 T& x0, T& x1, T& x2, T& x3) 00343 { 00344 x0 = load_be<T>(in, 0); 00345 x1 = load_be<T>(in, 1); 00346 x2 = load_be<T>(in, 2); 00347 x3 = load_be<T>(in, 3); 00348 } 00349 00350 /** 00351 * Load eight big-endian words 00352 * @param in a pointer to some bytes 00353 * @param x0 where the first word will be written 00354 * @param x1 where the second word will be written 00355 * @param x2 where the third word will be written 00356 * @param x3 where the fourth word will be written 00357 * @param x4 where the fifth word will be written 00358 * @param x5 where the sixth word will be written 00359 * @param x6 where the seventh word will be written 00360 * @param x7 where the eighth word will be written 00361 */ 00362 template<typename T> 00363 inline void load_be(const byte in[], 00364 T& x0, T& x1, T& x2, T& x3, 00365 T& x4, T& x5, T& x6, T& x7) 00366 { 00367 x0 = load_be<T>(in, 0); 00368 x1 = load_be<T>(in, 1); 00369 x2 = load_be<T>(in, 2); 00370 x3 = load_be<T>(in, 3); 00371 x4 = load_be<T>(in, 4); 00372 x5 = load_be<T>(in, 5); 00373 x6 = load_be<T>(in, 6); 00374 x7 = load_be<T>(in, 7); 00375 } 00376 00377 /** 00378 * Load a variable number of big-endian words 00379 * @param out the output array of words 00380 * @param in the input array of bytes 00381 * @param count how many words are in in 00382 */ 00383 template<typename T> 00384 inline void load_be(T out[], 00385 const byte in[], 00386 size_t count) 00387 { 00388 #if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) 00389 std::memcpy(out, in, sizeof(T)*count); 00390 00391 #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) 00392 const size_t blocks = count - (count % 4); 00393 const size_t left = count - blocks; 00394 00395 for(size_t i = 0; i != blocks; i += 4) 00396 bswap_4(out + i); 00397 00398 for(size_t i = 0; i != left; ++i) 00399 out[blocks+i] = reverse_bytes(out[blocks+i]); 00400 #endif 00401 00402 #else 00403 for(size_t i = 0; i != count; ++i) 00404 out[i] = load_be<T>(in, i); 00405 #endif 00406 } 00407 00408 /** 00409 * Store a big-endian u16bit 00410 * @param in the input u16bit 00411 * @param out the byte array to write to 00412 */ 00413 inline void store_be(u16bit in, byte out[2]) 00414 { 00415 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00416 *reinterpret_cast<u16bit*>(out) = BOTAN_ENDIAN_B2N(in); 00417 #else 00418 out[0] = get_byte(0, in); 00419 out[1] = get_byte(1, in); 00420 #endif 00421 } 00422 00423 /** 00424 * Store a little-endian u16bit 00425 * @param in the input u16bit 00426 * @param out the byte array to write to 00427 */ 00428 inline void store_le(u16bit in, byte out[2]) 00429 { 00430 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00431 *reinterpret_cast<u16bit*>(out) = BOTAN_ENDIAN_L2N(in); 00432 #else 00433 out[0] = get_byte(1, in); 00434 out[1] = get_byte(0, in); 00435 #endif 00436 } 00437 00438 /** 00439 * Store a big-endian u32bit 00440 * @param in the input u32bit 00441 * @param out the byte array to write to 00442 */ 00443 inline void store_be(u32bit in, byte out[4]) 00444 { 00445 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00446 *reinterpret_cast<u32bit*>(out) = BOTAN_ENDIAN_B2N(in); 00447 #else 00448 out[0] = get_byte(0, in); 00449 out[1] = get_byte(1, in); 00450 out[2] = get_byte(2, in); 00451 out[3] = get_byte(3, in); 00452 #endif 00453 } 00454 00455 /** 00456 * Store a little-endian u32bit 00457 * @param in the input u32bit 00458 * @param out the byte array to write to 00459 */ 00460 inline void store_le(u32bit in, byte out[4]) 00461 { 00462 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00463 *reinterpret_cast<u32bit*>(out) = BOTAN_ENDIAN_L2N(in); 00464 #else 00465 out[0] = get_byte(3, in); 00466 out[1] = get_byte(2, in); 00467 out[2] = get_byte(1, in); 00468 out[3] = get_byte(0, in); 00469 #endif 00470 } 00471 00472 /** 00473 * Store a big-endian u64bit 00474 * @param in the input u64bit 00475 * @param out the byte array to write to 00476 */ 00477 inline void store_be(u64bit in, byte out[8]) 00478 { 00479 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00480 *reinterpret_cast<u64bit*>(out) = BOTAN_ENDIAN_B2N(in); 00481 #else 00482 out[0] = get_byte(0, in); 00483 out[1] = get_byte(1, in); 00484 out[2] = get_byte(2, in); 00485 out[3] = get_byte(3, in); 00486 out[4] = get_byte(4, in); 00487 out[5] = get_byte(5, in); 00488 out[6] = get_byte(6, in); 00489 out[7] = get_byte(7, in); 00490 #endif 00491 } 00492 00493 /** 00494 * Store a little-endian u64bit 00495 * @param in the input u64bit 00496 * @param out the byte array to write to 00497 */ 00498 inline void store_le(u64bit in, byte out[8]) 00499 { 00500 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 00501 *reinterpret_cast<u64bit*>(out) = BOTAN_ENDIAN_L2N(in); 00502 #else 00503 out[0] = get_byte(7, in); 00504 out[1] = get_byte(6, in); 00505 out[2] = get_byte(5, in); 00506 out[3] = get_byte(4, in); 00507 out[4] = get_byte(3, in); 00508 out[5] = get_byte(2, in); 00509 out[6] = get_byte(1, in); 00510 out[7] = get_byte(0, in); 00511 #endif 00512 } 00513 00514 /** 00515 * Store two little-endian words 00516 * @param out the output byte array 00517 * @param x0 the first word 00518 * @param x1 the second word 00519 */ 00520 template<typename T> 00521 inline void store_le(byte out[], T x0, T x1) 00522 { 00523 store_le(x0, out + (0 * sizeof(T))); 00524 store_le(x1, out + (1 * sizeof(T))); 00525 } 00526 00527 /** 00528 * Store two big-endian words 00529 * @param out the output byte array 00530 * @param x0 the first word 00531 * @param x1 the second word 00532 */ 00533 template<typename T> 00534 inline void store_be(byte out[], T x0, T x1) 00535 { 00536 store_be(x0, out + (0 * sizeof(T))); 00537 store_be(x1, out + (1 * sizeof(T))); 00538 } 00539 00540 /** 00541 * Store four little-endian words 00542 * @param out the output byte array 00543 * @param x0 the first word 00544 * @param x1 the second word 00545 * @param x2 the third word 00546 * @param x3 the fourth word 00547 */ 00548 template<typename T> 00549 inline void store_le(byte out[], T x0, T x1, T x2, T x3) 00550 { 00551 store_le(x0, out + (0 * sizeof(T))); 00552 store_le(x1, out + (1 * sizeof(T))); 00553 store_le(x2, out + (2 * sizeof(T))); 00554 store_le(x3, out + (3 * sizeof(T))); 00555 } 00556 00557 /** 00558 * Store four big-endian words 00559 * @param out the output byte array 00560 * @param x0 the first word 00561 * @param x1 the second word 00562 * @param x2 the third word 00563 * @param x3 the fourth word 00564 */ 00565 template<typename T> 00566 inline void store_be(byte out[], T x0, T x1, T x2, T x3) 00567 { 00568 store_be(x0, out + (0 * sizeof(T))); 00569 store_be(x1, out + (1 * sizeof(T))); 00570 store_be(x2, out + (2 * sizeof(T))); 00571 store_be(x3, out + (3 * sizeof(T))); 00572 } 00573 00574 /** 00575 * Store eight little-endian words 00576 * @param out the output byte array 00577 * @param x0 the first word 00578 * @param x1 the second word 00579 * @param x2 the third word 00580 * @param x3 the fourth word 00581 * @param x4 the fifth word 00582 * @param x5 the sixth word 00583 * @param x6 the seventh word 00584 * @param x7 the eighth word 00585 */ 00586 template<typename T> 00587 inline void store_le(byte out[], T x0, T x1, T x2, T x3, 00588 T x4, T x5, T x6, T x7) 00589 { 00590 store_le(x0, out + (0 * sizeof(T))); 00591 store_le(x1, out + (1 * sizeof(T))); 00592 store_le(x2, out + (2 * sizeof(T))); 00593 store_le(x3, out + (3 * sizeof(T))); 00594 store_le(x4, out + (4 * sizeof(T))); 00595 store_le(x5, out + (5 * sizeof(T))); 00596 store_le(x6, out + (6 * sizeof(T))); 00597 store_le(x7, out + (7 * sizeof(T))); 00598 } 00599 00600 /** 00601 * Store eight big-endian words 00602 * @param out the output byte array 00603 * @param x0 the first word 00604 * @param x1 the second word 00605 * @param x2 the third word 00606 * @param x3 the fourth word 00607 * @param x4 the fifth word 00608 * @param x5 the sixth word 00609 * @param x6 the seventh word 00610 * @param x7 the eighth word 00611 */ 00612 template<typename T> 00613 inline void store_be(byte out[], T x0, T x1, T x2, T x3, 00614 T x4, T x5, T x6, T x7) 00615 { 00616 store_be(x0, out + (0 * sizeof(T))); 00617 store_be(x1, out + (1 * sizeof(T))); 00618 store_be(x2, out + (2 * sizeof(T))); 00619 store_be(x3, out + (3 * sizeof(T))); 00620 store_be(x4, out + (4 * sizeof(T))); 00621 store_be(x5, out + (5 * sizeof(T))); 00622 store_be(x6, out + (6 * sizeof(T))); 00623 store_be(x7, out + (7 * sizeof(T))); 00624 } 00625 00626 template<typename T> 00627 void copy_out_be(byte out[], size_t out_bytes, const T in[]) 00628 { 00629 while(out_bytes >= sizeof(T)) 00630 { 00631 store_be(in[0], out); 00632 out += sizeof(T); 00633 out_bytes -= sizeof(T); 00634 in += 1; 00635 } 00636 00637 for(size_t i = 0; i != out_bytes; ++i) 00638 out[i] = get_byte(i%8, in[0]); 00639 } 00640 00641 template<typename T, typename Alloc> 00642 void copy_out_vec_be(byte out[], size_t out_bytes, const std::vector<T, Alloc>& in) 00643 { 00644 copy_out_be(out, out_bytes, &in[0]); 00645 } 00646 00647 template<typename T> 00648 void copy_out_le(byte out[], size_t out_bytes, const T in[]) 00649 { 00650 while(out_bytes >= sizeof(T)) 00651 { 00652 store_le(in[0], out); 00653 out += sizeof(T); 00654 out_bytes -= sizeof(T); 00655 in += 1; 00656 } 00657 00658 for(size_t i = 0; i != out_bytes; ++i) 00659 out[i] = get_byte(sizeof(T) - 1 - (i % 8), in[0]); 00660 } 00661 00662 template<typename T, typename Alloc> 00663 void copy_out_vec_le(byte out[], size_t out_bytes, const std::vector<T, Alloc>& in) 00664 { 00665 copy_out_le(out, out_bytes, &in[0]); 00666 } 00667 00668 } 00669 00670 #endif