diff options
| author | deraadt <> | 2023-05-19 00:54:28 +0000 |
|---|---|---|
| committer | deraadt <> | 2023-05-19 00:54:28 +0000 |
| commit | 810ffccceee23ecfabf0344198f93c78f166076e (patch) | |
| tree | 2966339a1eb80b2ee20d3d4217893b5c4a50f75d | |
| parent | 7ffc9f677ed2e28353efec97b72894c9e457f44c (diff) | |
| download | openbsd-810ffccceee23ecfabf0344198f93c78f166076e.tar.gz openbsd-810ffccceee23ecfabf0344198f93c78f166076e.tar.bz2 openbsd-810ffccceee23ecfabf0344198f93c78f166076e.zip | |
backout alignment changes (breaking at least two architectures)
| -rw-r--r-- | src/lib/libcrypto/bn/bn_isqrt.c | 6 | ||||
| -rw-r--r-- | src/lib/libcrypto/crypto_internal.h | 55 | ||||
| -rw-r--r-- | src/lib/libcrypto/crypto_lock.c | 7 | ||||
| -rw-r--r-- | src/lib/libcrypto/sha/sha512.c | 121 |
4 files changed, 89 insertions, 100 deletions
diff --git a/src/lib/libcrypto/bn/bn_isqrt.c b/src/lib/libcrypto/bn/bn_isqrt.c index 1dff1b0562..d24a4a43ba 100644 --- a/src/lib/libcrypto/bn/bn_isqrt.c +++ b/src/lib/libcrypto/bn/bn_isqrt.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: bn_isqrt.c,v 1.8 2023/05/17 07:42:38 tb Exp $ */ | 1 | /* $OpenBSD: bn_isqrt.c,v 1.9 2023/05/19 00:54:28 deraadt Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> | 3 | * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> |
| 4 | * | 4 | * |
| @@ -22,7 +22,9 @@ | |||
| 22 | #include <openssl/err.h> | 22 | #include <openssl/err.h> |
| 23 | 23 | ||
| 24 | #include "bn_local.h" | 24 | #include "bn_local.h" |
| 25 | #include "crypto_internal.h" | 25 | |
| 26 | #define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \ | ||
| 27 | __attribute__((__unused__)) | ||
| 26 | 28 | ||
| 27 | /* | 29 | /* |
| 28 | * Calculate integer square root of |n| using a variant of Newton's method. | 30 | * Calculate integer square root of |n| using a variant of Newton's method. |
diff --git a/src/lib/libcrypto/crypto_internal.h b/src/lib/libcrypto/crypto_internal.h index 2e6ab82692..db3e99510b 100644 --- a/src/lib/libcrypto/crypto_internal.h +++ b/src/lib/libcrypto/crypto_internal.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: crypto_internal.h,v 1.4 2023/05/17 06:37:14 jsing Exp $ */ | 1 | /* $OpenBSD: crypto_internal.h,v 1.5 2023/05/19 00:54:27 deraadt Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2023 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2023 Joel Sing <jsing@openbsd.org> |
| 4 | * | 4 | * |
| @@ -22,34 +22,14 @@ | |||
| 22 | #ifndef HEADER_CRYPTO_INTERNAL_H | 22 | #ifndef HEADER_CRYPTO_INTERNAL_H |
| 23 | #define HEADER_CRYPTO_INTERNAL_H | 23 | #define HEADER_CRYPTO_INTERNAL_H |
| 24 | 24 | ||
| 25 | #define CTASSERT(x) \ | ||
| 26 | extern char _ctassert[(x) ? 1 : -1] __attribute__((__unused__)) | ||
| 27 | |||
| 28 | /* | ||
| 29 | * crypto_load_be32toh() loads a 32 bit unsigned big endian value as a 32 bit | ||
| 30 | * unsigned host endian value, from the specified address in memory. The memory | ||
| 31 | * address may have any alignment. | ||
| 32 | */ | ||
| 33 | #ifndef HAVE_CRYPTO_LOAD_BE32TOH | ||
| 34 | static inline uint32_t | ||
| 35 | crypto_load_be32toh(const void *src) | ||
| 36 | { | ||
| 37 | uint32_t v; | ||
| 38 | |||
| 39 | memcpy(&v, src, sizeof(v)); | ||
| 40 | |||
| 41 | return be32toh(v); | ||
| 42 | } | ||
| 43 | #endif | ||
| 44 | |||
| 45 | /* | 25 | /* |
| 46 | * crypto_store_htobe32() stores a 32 bit unsigned host endian value as a 32 bit | 26 | * crypto_store_htobe32() stores a 32 bit unsigned host endian value |
| 47 | * unsigned big endian value, at the specified address in memory. The memory | 27 | * as a 32 bit unsigned big endian value, at the specified location in |
| 48 | * address may have any alignment. | 28 | * memory. The memory location may have any alignment. |
| 49 | */ | 29 | */ |
| 50 | #ifndef HAVE_CRYPTO_STORE_HTOBE32 | 30 | #ifndef HAVE_CRYPTO_STORE_HTOBE32 |
| 51 | static inline void | 31 | static inline void |
| 52 | crypto_store_htobe32(void *dst, uint32_t v) | 32 | crypto_store_htobe32(uint8_t *dst, uint32_t v) |
| 53 | { | 33 | { |
| 54 | v = htobe32(v); | 34 | v = htobe32(v); |
| 55 | memcpy(dst, &v, sizeof(v)); | 35 | memcpy(dst, &v, sizeof(v)); |
| @@ -57,30 +37,13 @@ crypto_store_htobe32(void *dst, uint32_t v) | |||
| 57 | #endif | 37 | #endif |
| 58 | 38 | ||
| 59 | /* | 39 | /* |
| 60 | * crypto_load_be64toh() loads a 64 bit unsigned big endian value as a 64 bit | 40 | * crypto_store_htobe64() stores a 64 bit unsigned host endian value |
| 61 | * unsigned host endian value, from the specified address in memory. The memory | 41 | * as a 64 bit unsigned big endian value, at the specified location in |
| 62 | * address may have any alignment. | 42 | * memory. The memory location may have any alignment. |
| 63 | */ | ||
| 64 | #ifndef HAVE_CRYPTO_LOAD_BE64TOH | ||
| 65 | static inline uint64_t | ||
| 66 | crypto_load_be64toh(const void *src) | ||
| 67 | { | ||
| 68 | uint64_t v; | ||
| 69 | |||
| 70 | memcpy(&v, src, sizeof(v)); | ||
| 71 | |||
| 72 | return be64toh(v); | ||
| 73 | } | ||
| 74 | #endif | ||
| 75 | |||
| 76 | /* | ||
| 77 | * crypto_store_htobe64() stores a 64 bit unsigned host endian value as a 64 bit | ||
| 78 | * unsigned big endian value, at the specified address in memory. The memory | ||
| 79 | * address may have any alignment. | ||
| 80 | */ | 43 | */ |
| 81 | #ifndef HAVE_CRYPTO_STORE_HTOBE64 | 44 | #ifndef HAVE_CRYPTO_STORE_HTOBE64 |
| 82 | static inline void | 45 | static inline void |
| 83 | crypto_store_htobe64(void *dst, uint64_t v) | 46 | crypto_store_htobe64(uint8_t *dst, uint64_t v) |
| 84 | { | 47 | { |
| 85 | v = htobe64(v); | 48 | v = htobe64(v); |
| 86 | memcpy(dst, &v, sizeof(v)); | 49 | memcpy(dst, &v, sizeof(v)); |
diff --git a/src/lib/libcrypto/crypto_lock.c b/src/lib/libcrypto/crypto_lock.c index 5b1d1b090b..bd8315c264 100644 --- a/src/lib/libcrypto/crypto_lock.c +++ b/src/lib/libcrypto/crypto_lock.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: crypto_lock.c,v 1.3 2023/05/17 07:42:38 tb Exp $ */ | 1 | /* $OpenBSD: crypto_lock.c,v 1.4 2023/05/19 00:54:27 deraadt Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2018 Brent Cook <bcook@openbsd.org> | 3 | * Copyright (c) 2018 Brent Cook <bcook@openbsd.org> |
| 4 | * | 4 | * |
| @@ -19,8 +19,6 @@ | |||
| 19 | 19 | ||
| 20 | #include <openssl/crypto.h> | 20 | #include <openssl/crypto.h> |
| 21 | 21 | ||
| 22 | #include "crypto_internal.h" | ||
| 23 | |||
| 24 | static pthread_mutex_t locks[] = { | 22 | static pthread_mutex_t locks[] = { |
| 25 | PTHREAD_MUTEX_INITIALIZER, | 23 | PTHREAD_MUTEX_INITIALIZER, |
| 26 | PTHREAD_MUTEX_INITIALIZER, | 24 | PTHREAD_MUTEX_INITIALIZER, |
| @@ -65,6 +63,9 @@ static pthread_mutex_t locks[] = { | |||
| 65 | PTHREAD_MUTEX_INITIALIZER, | 63 | PTHREAD_MUTEX_INITIALIZER, |
| 66 | }; | 64 | }; |
| 67 | 65 | ||
| 66 | #define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \ | ||
| 67 | __attribute__((__unused__)) | ||
| 68 | |||
| 68 | CTASSERT((sizeof(locks) / sizeof(*locks)) == CRYPTO_NUM_LOCKS); | 69 | CTASSERT((sizeof(locks) / sizeof(*locks)) == CRYPTO_NUM_LOCKS); |
| 69 | 70 | ||
| 70 | void | 71 | void |
diff --git a/src/lib/libcrypto/sha/sha512.c b/src/lib/libcrypto/sha/sha512.c index c88ef057dd..94e55a3d2a 100644 --- a/src/lib/libcrypto/sha/sha512.c +++ b/src/lib/libcrypto/sha/sha512.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: sha512.c,v 1.37 2023/05/17 06:37:14 jsing Exp $ */ | 1 | /* $OpenBSD: sha512.c,v 1.38 2023/05/19 00:54:28 deraadt Exp $ */ |
| 2 | /* ==================================================================== | 2 | /* ==================================================================== |
| 3 | * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. | 3 | * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. |
| 4 | * | 4 | * |
| @@ -66,8 +66,9 @@ | |||
| 66 | 66 | ||
| 67 | #if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA512) | 67 | #if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA512) |
| 68 | 68 | ||
| 69 | /* Ensure that SHA_LONG64 and uint64_t are equivalent. */ | 69 | #if !defined(__STRICT_ALIGNMENT) || defined(SHA512_ASM) |
| 70 | CTASSERT(sizeof(SHA_LONG64) == sizeof(uint64_t)); | 70 | #define SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA |
| 71 | #endif | ||
| 71 | 72 | ||
| 72 | #ifdef SHA512_ASM | 73 | #ifdef SHA512_ASM |
| 73 | void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num); | 74 | void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num); |
| @@ -117,6 +118,31 @@ static const SHA_LONG64 K512[80] = { | |||
| 117 | U64(0x5fcb6fab3ad6faec), U64(0x6c44198c4a475817), | 118 | U64(0x5fcb6fab3ad6faec), U64(0x6c44198c4a475817), |
| 118 | }; | 119 | }; |
| 119 | 120 | ||
| 121 | #if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) | ||
| 122 | # if defined(__x86_64) || defined(__x86_64__) | ||
| 123 | # define PULL64(x) ({ SHA_LONG64 ret=*((const SHA_LONG64 *)(&(x))); \ | ||
| 124 | asm ("bswapq %0" \ | ||
| 125 | : "=r"(ret) \ | ||
| 126 | : "0"(ret)); ret; }) | ||
| 127 | # elif (defined(__i386) || defined(__i386__)) | ||
| 128 | # define PULL64(x) ({ const unsigned int *p=(const unsigned int *)(&(x));\ | ||
| 129 | unsigned int hi=p[0],lo=p[1]; \ | ||
| 130 | asm ("bswapl %0; bswapl %1;" \ | ||
| 131 | : "=r"(lo),"=r"(hi) \ | ||
| 132 | : "0"(lo),"1"(hi)); \ | ||
| 133 | ((SHA_LONG64)hi)<<32|lo; }) | ||
| 134 | # endif | ||
| 135 | #endif | ||
| 136 | |||
| 137 | #ifndef PULL64 | ||
| 138 | #if BYTE_ORDER == BIG_ENDIAN | ||
| 139 | #define PULL64(x) (x) | ||
| 140 | #else | ||
| 141 | #define B(x, j) (((SHA_LONG64)(*(((const unsigned char *)(&x))+j)))<<((7-j)*8)) | ||
| 142 | #define PULL64(x) (B(x,0)|B(x,1)|B(x,2)|B(x,3)|B(x,4)|B(x,5)|B(x,6)|B(x,7)) | ||
| 143 | #endif | ||
| 144 | #endif | ||
| 145 | |||
| 120 | #define ROTR(x, s) crypto_ror_u64(x, s) | 146 | #define ROTR(x, s) crypto_ror_u64(x, s) |
| 121 | 147 | ||
| 122 | #define Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39)) | 148 | #define Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39)) |
| @@ -159,60 +185,37 @@ sha512_block_data_order(SHA512_CTX *ctx, const void *_in, size_t num) | |||
| 159 | g = ctx->h[6]; | 185 | g = ctx->h[6]; |
| 160 | h = ctx->h[7]; | 186 | h = ctx->h[7]; |
| 161 | 187 | ||
| 162 | if ((uintptr_t)in % sizeof(SHA_LONG64) == 0) { | 188 | X[0] = PULL64(in[0]); |
| 163 | /* Input is 64 bit aligned. */ | ||
| 164 | X[0] = be64toh(in[0]); | ||
| 165 | X[1] = be64toh(in[1]); | ||
| 166 | X[2] = be64toh(in[2]); | ||
| 167 | X[3] = be64toh(in[3]); | ||
| 168 | X[4] = be64toh(in[4]); | ||
| 169 | X[5] = be64toh(in[5]); | ||
| 170 | X[6] = be64toh(in[6]); | ||
| 171 | X[7] = be64toh(in[7]); | ||
| 172 | X[8] = be64toh(in[8]); | ||
| 173 | X[9] = be64toh(in[9]); | ||
| 174 | X[10] = be64toh(in[10]); | ||
| 175 | X[11] = be64toh(in[11]); | ||
| 176 | X[12] = be64toh(in[12]); | ||
| 177 | X[13] = be64toh(in[13]); | ||
| 178 | X[14] = be64toh(in[14]); | ||
| 179 | X[15] = be64toh(in[15]); | ||
| 180 | } else { | ||
| 181 | /* Input is not 64 bit aligned. */ | ||
| 182 | X[0] = crypto_load_be64toh(&in[0]); | ||
| 183 | X[1] = crypto_load_be64toh(&in[1]); | ||
| 184 | X[2] = crypto_load_be64toh(&in[2]); | ||
| 185 | X[3] = crypto_load_be64toh(&in[3]); | ||
| 186 | X[4] = crypto_load_be64toh(&in[4]); | ||
| 187 | X[5] = crypto_load_be64toh(&in[5]); | ||
| 188 | X[6] = crypto_load_be64toh(&in[6]); | ||
| 189 | X[7] = crypto_load_be64toh(&in[7]); | ||
| 190 | X[8] = crypto_load_be64toh(&in[8]); | ||
| 191 | X[9] = crypto_load_be64toh(&in[9]); | ||
| 192 | X[10] = crypto_load_be64toh(&in[10]); | ||
| 193 | X[11] = crypto_load_be64toh(&in[11]); | ||
| 194 | X[12] = crypto_load_be64toh(&in[12]); | ||
| 195 | X[13] = crypto_load_be64toh(&in[13]); | ||
| 196 | X[14] = crypto_load_be64toh(&in[14]); | ||
| 197 | X[15] = crypto_load_be64toh(&in[15]); | ||
| 198 | } | ||
| 199 | in += SHA_LBLOCK; | ||
| 200 | |||
| 201 | ROUND_00_15(0, a, b, c, d, e, f, g, h, X[0]); | 189 | ROUND_00_15(0, a, b, c, d, e, f, g, h, X[0]); |
| 190 | X[1] = PULL64(in[1]); | ||
| 202 | ROUND_00_15(1, h, a, b, c, d, e, f, g, X[1]); | 191 | ROUND_00_15(1, h, a, b, c, d, e, f, g, X[1]); |
| 192 | X[2] = PULL64(in[2]); | ||
| 203 | ROUND_00_15(2, g, h, a, b, c, d, e, f, X[2]); | 193 | ROUND_00_15(2, g, h, a, b, c, d, e, f, X[2]); |
| 194 | X[3] = PULL64(in[3]); | ||
| 204 | ROUND_00_15(3, f, g, h, a, b, c, d, e, X[3]); | 195 | ROUND_00_15(3, f, g, h, a, b, c, d, e, X[3]); |
| 196 | X[4] = PULL64(in[4]); | ||
| 205 | ROUND_00_15(4, e, f, g, h, a, b, c, d, X[4]); | 197 | ROUND_00_15(4, e, f, g, h, a, b, c, d, X[4]); |
| 198 | X[5] = PULL64(in[5]); | ||
| 206 | ROUND_00_15(5, d, e, f, g, h, a, b, c, X[5]); | 199 | ROUND_00_15(5, d, e, f, g, h, a, b, c, X[5]); |
| 200 | X[6] = PULL64(in[6]); | ||
| 207 | ROUND_00_15(6, c, d, e, f, g, h, a, b, X[6]); | 201 | ROUND_00_15(6, c, d, e, f, g, h, a, b, X[6]); |
| 202 | X[7] = PULL64(in[7]); | ||
| 208 | ROUND_00_15(7, b, c, d, e, f, g, h, a, X[7]); | 203 | ROUND_00_15(7, b, c, d, e, f, g, h, a, X[7]); |
| 204 | X[8] = PULL64(in[8]); | ||
| 209 | ROUND_00_15(8, a, b, c, d, e, f, g, h, X[8]); | 205 | ROUND_00_15(8, a, b, c, d, e, f, g, h, X[8]); |
| 206 | X[9] = PULL64(in[9]); | ||
| 210 | ROUND_00_15(9, h, a, b, c, d, e, f, g, X[9]); | 207 | ROUND_00_15(9, h, a, b, c, d, e, f, g, X[9]); |
| 208 | X[10] = PULL64(in[10]); | ||
| 211 | ROUND_00_15(10, g, h, a, b, c, d, e, f, X[10]); | 209 | ROUND_00_15(10, g, h, a, b, c, d, e, f, X[10]); |
| 210 | X[11] = PULL64(in[11]); | ||
| 212 | ROUND_00_15(11, f, g, h, a, b, c, d, e, X[11]); | 211 | ROUND_00_15(11, f, g, h, a, b, c, d, e, X[11]); |
| 212 | X[12] = PULL64(in[12]); | ||
| 213 | ROUND_00_15(12, e, f, g, h, a, b, c, d, X[12]); | 213 | ROUND_00_15(12, e, f, g, h, a, b, c, d, X[12]); |
| 214 | X[13] = PULL64(in[13]); | ||
| 214 | ROUND_00_15(13, d, e, f, g, h, a, b, c, X[13]); | 215 | ROUND_00_15(13, d, e, f, g, h, a, b, c, X[13]); |
| 216 | X[14] = PULL64(in[14]); | ||
| 215 | ROUND_00_15(14, c, d, e, f, g, h, a, b, X[14]); | 217 | ROUND_00_15(14, c, d, e, f, g, h, a, b, X[14]); |
| 218 | X[15] = PULL64(in[15]); | ||
| 216 | ROUND_00_15(15, b, c, d, e, f, g, h, a, X[15]); | 219 | ROUND_00_15(15, b, c, d, e, f, g, h, a, X[15]); |
| 217 | 220 | ||
| 218 | for (i = 16; i < 80; i += 16) { | 221 | for (i = 16; i < 80; i += 16) { |
| @@ -242,6 +245,8 @@ sha512_block_data_order(SHA512_CTX *ctx, const void *_in, size_t num) | |||
| 242 | ctx->h[5] += f; | 245 | ctx->h[5] += f; |
| 243 | ctx->h[6] += g; | 246 | ctx->h[6] += g; |
| 244 | ctx->h[7] += h; | 247 | ctx->h[7] += h; |
| 248 | |||
| 249 | in += SHA_LBLOCK; | ||
| 245 | } | 250 | } |
| 246 | } | 251 | } |
| 247 | 252 | ||
| @@ -318,15 +323,21 @@ SHA512_Init(SHA512_CTX *c) | |||
| 318 | void | 323 | void |
| 319 | SHA512_Transform(SHA512_CTX *c, const unsigned char *data) | 324 | SHA512_Transform(SHA512_CTX *c, const unsigned char *data) |
| 320 | { | 325 | { |
| 326 | #ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA | ||
| 327 | if ((size_t)data % sizeof(c->u.d[0]) != 0) { | ||
| 328 | memcpy(c->u.p, data, sizeof(c->u.p)); | ||
| 329 | data = c->u.p; | ||
| 330 | } | ||
| 331 | #endif | ||
| 321 | sha512_block_data_order(c, data, 1); | 332 | sha512_block_data_order(c, data, 1); |
| 322 | } | 333 | } |
| 323 | 334 | ||
| 324 | int | 335 | int |
| 325 | SHA512_Update(SHA512_CTX *c, const void *_data, size_t len) | 336 | SHA512_Update(SHA512_CTX *c, const void *_data, size_t len) |
| 326 | { | 337 | { |
| 327 | const unsigned char *data = _data; | 338 | SHA_LONG64 l; |
| 328 | unsigned char *p = c->u.p; | 339 | unsigned char *p = c->u.p; |
| 329 | SHA_LONG64 l; | 340 | const unsigned char *data = (const unsigned char *)_data; |
| 330 | 341 | ||
| 331 | if (len == 0) | 342 | if (len == 0) |
| 332 | return 1; | 343 | return 1; |
| @@ -355,10 +366,22 @@ SHA512_Update(SHA512_CTX *c, const void *_data, size_t len) | |||
| 355 | } | 366 | } |
| 356 | 367 | ||
| 357 | if (len >= sizeof(c->u)) { | 368 | if (len >= sizeof(c->u)) { |
| 358 | sha512_block_data_order(c, data, len/sizeof(c->u)); | 369 | #ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA |
| 359 | data += len; | 370 | if ((size_t)data % sizeof(c->u.d[0]) != 0) { |
| 360 | len %= sizeof(c->u); | 371 | while (len >= sizeof(c->u)) { |
| 361 | data -= len; | 372 | memcpy(p, data, sizeof(c->u)); |
| 373 | sha512_block_data_order(c, p, 1); | ||
| 374 | len -= sizeof(c->u); | ||
| 375 | data += sizeof(c->u); | ||
| 376 | } | ||
| 377 | } else | ||
| 378 | #endif | ||
| 379 | { | ||
| 380 | sha512_block_data_order(c, data, len/sizeof(c->u)); | ||
| 381 | data += len; | ||
| 382 | len %= sizeof(c->u); | ||
| 383 | data -= len; | ||
| 384 | } | ||
| 362 | } | 385 | } |
| 363 | 386 | ||
| 364 | if (len != 0) { | 387 | if (len != 0) { |
