bufhelp.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /* bufhelp.h - Some buffer manipulation helpers
  2. * Copyright (C) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
  3. *
  4. * This file is part of Libgcrypt.
  5. *
  6. * Libgcrypt is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as
  8. * published by the Free Software Foundation; either version 2.1 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * Libgcrypt is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef GCRYPT_BUFHELP_H
  20. #define GCRYPT_BUFHELP_H
  21. #include "bithelp.h"
  22. #undef BUFHELP_FAST_UNALIGNED_ACCESS
  23. #if defined(HAVE_GCC_ATTRIBUTE_PACKED) && \
  24. defined(HAVE_GCC_ATTRIBUTE_ALIGNED) && \
  25. (defined(__i386__) || defined(__x86_64__) || \
  26. (defined(__arm__) && defined(__ARM_FEATURE_UNALIGNED)) || \
  27. defined(__aarch64__))
  28. /* These architectures are able of unaligned memory accesses and can
  29. handle those fast.
  30. */
  31. # define BUFHELP_FAST_UNALIGNED_ACCESS 1
  32. #endif
  33. #ifdef BUFHELP_FAST_UNALIGNED_ACCESS
  34. /* Define type with one-byte alignment on architectures with fast unaligned
  35. memory accesses.
  36. */
  37. typedef struct bufhelp_int_s
  38. {
  39. uintptr_t a;
  40. } __attribute__((packed, aligned(1))) bufhelp_int_t;
  41. #else
  42. /* Define type with default alignment for other architectures (unaligned
  43. accessed handled in per byte loops).
  44. */
  45. typedef struct bufhelp_int_s
  46. {
  47. uintptr_t a;
  48. } bufhelp_int_t;
  49. #endif
  50. /* Optimized function for small buffer copying */
  51. static inline void
  52. buf_cpy(void *_dst, const void *_src, size_t len)
  53. {
  54. #if __GNUC__ >= 4 && (defined(__x86_64__) || defined(__i386__))
  55. /* For AMD64 and i386, memcpy is faster. */
  56. memcpy(_dst, _src, len);
  57. #else
  58. byte *dst = _dst;
  59. const byte *src = _src;
  60. bufhelp_int_t *ldst;
  61. const bufhelp_int_t *lsrc;
  62. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  63. const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
  64. /* Skip fast processing if buffers are unaligned. */
  65. if (((uintptr_t)dst | (uintptr_t)src) & longmask)
  66. goto do_bytes;
  67. #endif
  68. ldst = (bufhelp_int_t *)(void *)dst;
  69. lsrc = (const bufhelp_int_t *)(const void *)src;
  70. for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
  71. (ldst++)->a = (lsrc++)->a;
  72. dst = (byte *)ldst;
  73. src = (const byte *)lsrc;
  74. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  75. do_bytes:
  76. #endif
  77. /* Handle tail. */
  78. for (; len; len--)
  79. *dst++ = *src++;
  80. #endif /*__GNUC__ >= 4 && (__x86_64__ || __i386__)*/
  81. }
  82. /* Optimized function for buffer xoring */
  83. static inline void
  84. buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len)
  85. {
  86. byte *dst = _dst;
  87. const byte *src1 = _src1;
  88. const byte *src2 = _src2;
  89. bufhelp_int_t *ldst;
  90. const bufhelp_int_t *lsrc1, *lsrc2;
  91. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  92. const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
  93. /* Skip fast processing if buffers are unaligned. */
  94. if (((uintptr_t)dst | (uintptr_t)src1 | (uintptr_t)src2) & longmask)
  95. goto do_bytes;
  96. #endif
  97. ldst = (bufhelp_int_t *)(void *)dst;
  98. lsrc1 = (const bufhelp_int_t *)(const void *)src1;
  99. lsrc2 = (const bufhelp_int_t *)(const void *)src2;
  100. for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
  101. (ldst++)->a = (lsrc1++)->a ^ (lsrc2++)->a;
  102. dst = (byte *)ldst;
  103. src1 = (const byte *)lsrc1;
  104. src2 = (const byte *)lsrc2;
  105. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  106. do_bytes:
  107. #endif
  108. /* Handle tail. */
  109. for (; len; len--)
  110. *dst++ = *src1++ ^ *src2++;
  111. }
  112. /* Optimized function for in-place buffer xoring. */
  113. static inline void
  114. buf_xor_1(void *_dst, const void *_src, size_t len)
  115. {
  116. byte *dst = _dst;
  117. const byte *src = _src;
  118. bufhelp_int_t *ldst;
  119. const bufhelp_int_t *lsrc;
  120. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  121. const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
  122. /* Skip fast processing if buffers are unaligned. */
  123. if (((uintptr_t)dst | (uintptr_t)src) & longmask)
  124. goto do_bytes;
  125. #endif
  126. ldst = (bufhelp_int_t *)(void *)dst;
  127. lsrc = (const bufhelp_int_t *)(const void *)src;
  128. for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
  129. (ldst++)->a ^= (lsrc++)->a;
  130. dst = (byte *)ldst;
  131. src = (const byte *)lsrc;
  132. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  133. do_bytes:
  134. #endif
  135. /* Handle tail. */
  136. for (; len; len--)
  137. *dst++ ^= *src++;
  138. }
  139. /* Optimized function for buffer xoring with two destination buffers. Used
  140. mainly by CFB mode encryption. */
  141. static inline void
  142. buf_xor_2dst(void *_dst1, void *_dst2, const void *_src, size_t len)
  143. {
  144. byte *dst1 = _dst1;
  145. byte *dst2 = _dst2;
  146. const byte *src = _src;
  147. bufhelp_int_t *ldst1, *ldst2;
  148. const bufhelp_int_t *lsrc;
  149. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  150. const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
  151. /* Skip fast processing if buffers are unaligned. */
  152. if (((uintptr_t)src | (uintptr_t)dst1 | (uintptr_t)dst2) & longmask)
  153. goto do_bytes;
  154. #endif
  155. ldst1 = (bufhelp_int_t *)(void *)dst1;
  156. ldst2 = (bufhelp_int_t *)(void *)dst2;
  157. lsrc = (const bufhelp_int_t *)(const void *)src;
  158. for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
  159. (ldst1++)->a = ((ldst2++)->a ^= (lsrc++)->a);
  160. dst1 = (byte *)ldst1;
  161. dst2 = (byte *)ldst2;
  162. src = (const byte *)lsrc;
  163. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  164. do_bytes:
  165. #endif
  166. /* Handle tail. */
  167. for (; len; len--)
  168. *dst1++ = (*dst2++ ^= *src++);
  169. }
  170. /* Optimized function for combined buffer xoring and copying. Used by mainly
  171. CBC mode decryption. */
  172. static inline void
  173. buf_xor_n_copy_2(void *_dst_xor, const void *_src_xor, void *_srcdst_cpy,
  174. const void *_src_cpy, size_t len)
  175. {
  176. byte *dst_xor = _dst_xor;
  177. byte *srcdst_cpy = _srcdst_cpy;
  178. const byte *src_xor = _src_xor;
  179. const byte *src_cpy = _src_cpy;
  180. byte temp;
  181. bufhelp_int_t *ldst_xor, *lsrcdst_cpy;
  182. const bufhelp_int_t *lsrc_cpy, *lsrc_xor;
  183. uintptr_t ltemp;
  184. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  185. const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
  186. /* Skip fast processing if buffers are unaligned. */
  187. if (((uintptr_t)src_cpy | (uintptr_t)src_xor | (uintptr_t)dst_xor |
  188. (uintptr_t)srcdst_cpy) & longmask)
  189. goto do_bytes;
  190. #endif
  191. ldst_xor = (bufhelp_int_t *)(void *)dst_xor;
  192. lsrc_xor = (const bufhelp_int_t *)(void *)src_xor;
  193. lsrcdst_cpy = (bufhelp_int_t *)(void *)srcdst_cpy;
  194. lsrc_cpy = (const bufhelp_int_t *)(const void *)src_cpy;
  195. for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
  196. {
  197. ltemp = (lsrc_cpy++)->a;
  198. (ldst_xor++)->a = (lsrcdst_cpy)->a ^ (lsrc_xor++)->a;
  199. (lsrcdst_cpy++)->a = ltemp;
  200. }
  201. dst_xor = (byte *)ldst_xor;
  202. src_xor = (const byte *)lsrc_xor;
  203. srcdst_cpy = (byte *)lsrcdst_cpy;
  204. src_cpy = (const byte *)lsrc_cpy;
  205. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  206. do_bytes:
  207. #endif
  208. /* Handle tail. */
  209. for (; len; len--)
  210. {
  211. temp = *src_cpy++;
  212. *dst_xor++ = *srcdst_cpy ^ *src_xor++;
  213. *srcdst_cpy++ = temp;
  214. }
  215. }
  216. /* Optimized function for combined buffer xoring and copying. Used by mainly
  217. CFB mode decryption. */
  218. static inline void
  219. buf_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, size_t len)
  220. {
  221. buf_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, len);
  222. }
  223. /* Constant-time compare of two buffers. Returns 1 if buffers are equal,
  224. and 0 if buffers differ. */
  225. static inline int
  226. buf_eq_const(const void *_a, const void *_b, size_t len)
  227. {
  228. const byte *a = _a;
  229. const byte *b = _b;
  230. size_t diff, i;
  231. /* Constant-time compare. */
  232. for (i = 0, diff = 0; i < len; i++)
  233. diff -= !!(a[i] - b[i]);
  234. return !diff;
  235. }
  236. #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
  237. /* Functions for loading and storing unaligned u32 values of different
  238. endianness. */
  239. static inline u32 buf_get_be32(const void *_buf)
  240. {
  241. const byte *in = _buf;
  242. return ((u32)in[0] << 24) | ((u32)in[1] << 16) | \
  243. ((u32)in[2] << 8) | (u32)in[3];
  244. }
  245. static inline u32 buf_get_le32(const void *_buf)
  246. {
  247. const byte *in = _buf;
  248. return ((u32)in[3] << 24) | ((u32)in[2] << 16) | \
  249. ((u32)in[1] << 8) | (u32)in[0];
  250. }
  251. static inline void buf_put_be32(void *_buf, u32 val)
  252. {
  253. byte *out = _buf;
  254. out[0] = val >> 24;
  255. out[1] = val >> 16;
  256. out[2] = val >> 8;
  257. out[3] = val;
  258. }
  259. static inline void buf_put_le32(void *_buf, u32 val)
  260. {
  261. byte *out = _buf;
  262. out[3] = val >> 24;
  263. out[2] = val >> 16;
  264. out[1] = val >> 8;
  265. out[0] = val;
  266. }
  267. /* Functions for loading and storing unaligned u64 values of different
  268. endianness. */
  269. static inline u64 buf_get_be64(const void *_buf)
  270. {
  271. const byte *in = _buf;
  272. return ((u64)in[0] << 56) | ((u64)in[1] << 48) | \
  273. ((u64)in[2] << 40) | ((u64)in[3] << 32) | \
  274. ((u64)in[4] << 24) | ((u64)in[5] << 16) | \
  275. ((u64)in[6] << 8) | (u64)in[7];
  276. }
  277. static inline u64 buf_get_le64(const void *_buf)
  278. {
  279. const byte *in = _buf;
  280. return ((u64)in[7] << 56) | ((u64)in[6] << 48) | \
  281. ((u64)in[5] << 40) | ((u64)in[4] << 32) | \
  282. ((u64)in[3] << 24) | ((u64)in[2] << 16) | \
  283. ((u64)in[1] << 8) | (u64)in[0];
  284. }
  285. static inline void buf_put_be64(void *_buf, u64 val)
  286. {
  287. byte *out = _buf;
  288. out[0] = val >> 56;
  289. out[1] = val >> 48;
  290. out[2] = val >> 40;
  291. out[3] = val >> 32;
  292. out[4] = val >> 24;
  293. out[5] = val >> 16;
  294. out[6] = val >> 8;
  295. out[7] = val;
  296. }
  297. static inline void buf_put_le64(void *_buf, u64 val)
  298. {
  299. byte *out = _buf;
  300. out[7] = val >> 56;
  301. out[6] = val >> 48;
  302. out[5] = val >> 40;
  303. out[4] = val >> 32;
  304. out[3] = val >> 24;
  305. out[2] = val >> 16;
  306. out[1] = val >> 8;
  307. out[0] = val;
  308. }
  309. #else /*BUFHELP_FAST_UNALIGNED_ACCESS*/
  310. typedef struct bufhelp_u32_s
  311. {
  312. u32 a;
  313. } __attribute__((packed, aligned(1))) bufhelp_u32_t;
  314. /* Functions for loading and storing unaligned u32 values of different
  315. endianness. */
  316. static inline u32 buf_get_be32(const void *_buf)
  317. {
  318. return be_bswap32(((const bufhelp_u32_t *)_buf)->a);
  319. }
  320. static inline u32 buf_get_le32(const void *_buf)
  321. {
  322. return le_bswap32(((const bufhelp_u32_t *)_buf)->a);
  323. }
  324. static inline void buf_put_be32(void *_buf, u32 val)
  325. {
  326. bufhelp_u32_t *out = _buf;
  327. out->a = be_bswap32(val);
  328. }
  329. static inline void buf_put_le32(void *_buf, u32 val)
  330. {
  331. bufhelp_u32_t *out = _buf;
  332. out->a = le_bswap32(val);
  333. }
  334. typedef struct bufhelp_u64_s
  335. {
  336. u64 a;
  337. } __attribute__((packed, aligned(1))) bufhelp_u64_t;
  338. /* Functions for loading and storing unaligned u64 values of different
  339. endianness. */
  340. static inline u64 buf_get_be64(const void *_buf)
  341. {
  342. return be_bswap64(((const bufhelp_u64_t *)_buf)->a);
  343. }
  344. static inline u64 buf_get_le64(const void *_buf)
  345. {
  346. return le_bswap64(((const bufhelp_u64_t *)_buf)->a);
  347. }
  348. static inline void buf_put_be64(void *_buf, u64 val)
  349. {
  350. bufhelp_u64_t *out = _buf;
  351. out->a = be_bswap64(val);
  352. }
  353. static inline void buf_put_le64(void *_buf, u64 val)
  354. {
  355. bufhelp_u64_t *out = _buf;
  356. out->a = le_bswap64(val);
  357. }
  358. #endif /*BUFHELP_FAST_UNALIGNED_ACCESS*/
  359. #endif /*GCRYPT_BUFHELP_H*/