Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* |
michael@0 | 2 | * desblapi.c |
michael@0 | 3 | * |
michael@0 | 4 | * core source file for DES-150 library |
michael@0 | 5 | * Implement DES Modes of Operation and Triple-DES. |
michael@0 | 6 | * Adapt DES-150 to blapi API. |
michael@0 | 7 | * |
michael@0 | 8 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 9 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 10 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 11 | |
michael@0 | 12 | #ifdef FREEBL_NO_DEPEND |
michael@0 | 13 | #include "stubs.h" |
michael@0 | 14 | #endif |
michael@0 | 15 | |
michael@0 | 16 | #include "des.h" |
michael@0 | 17 | #include <stddef.h> |
michael@0 | 18 | #include "secerr.h" |
michael@0 | 19 | |
michael@0 | 20 | #if defined(NSS_X86_OR_X64) |
michael@0 | 21 | /* Intel X86 CPUs do unaligned loads and stores without complaint. */ |
michael@0 | 22 | #define COPY8B(to, from, ptr) \ |
michael@0 | 23 | HALFPTR(to)[0] = HALFPTR(from)[0]; \ |
michael@0 | 24 | HALFPTR(to)[1] = HALFPTR(from)[1]; |
michael@0 | 25 | #elif defined(USE_MEMCPY) |
michael@0 | 26 | #define COPY8B(to, from, ptr) memcpy(to, from, 8) |
michael@0 | 27 | #else |
michael@0 | 28 | #define COPY8B(to, from, ptr) \ |
michael@0 | 29 | if (((ptrdiff_t)(ptr) & 0x3) == 0) { \ |
michael@0 | 30 | HALFPTR(to)[0] = HALFPTR(from)[0]; \ |
michael@0 | 31 | HALFPTR(to)[1] = HALFPTR(from)[1]; \ |
michael@0 | 32 | } else if (((ptrdiff_t)(ptr) & 0x1) == 0) { \ |
michael@0 | 33 | SHORTPTR(to)[0] = SHORTPTR(from)[0]; \ |
michael@0 | 34 | SHORTPTR(to)[1] = SHORTPTR(from)[1]; \ |
michael@0 | 35 | SHORTPTR(to)[2] = SHORTPTR(from)[2]; \ |
michael@0 | 36 | SHORTPTR(to)[3] = SHORTPTR(from)[3]; \ |
michael@0 | 37 | } else { \ |
michael@0 | 38 | BYTEPTR(to)[0] = BYTEPTR(from)[0]; \ |
michael@0 | 39 | BYTEPTR(to)[1] = BYTEPTR(from)[1]; \ |
michael@0 | 40 | BYTEPTR(to)[2] = BYTEPTR(from)[2]; \ |
michael@0 | 41 | BYTEPTR(to)[3] = BYTEPTR(from)[3]; \ |
michael@0 | 42 | BYTEPTR(to)[4] = BYTEPTR(from)[4]; \ |
michael@0 | 43 | BYTEPTR(to)[5] = BYTEPTR(from)[5]; \ |
michael@0 | 44 | BYTEPTR(to)[6] = BYTEPTR(from)[6]; \ |
michael@0 | 45 | BYTEPTR(to)[7] = BYTEPTR(from)[7]; \ |
michael@0 | 46 | } |
michael@0 | 47 | #endif |
michael@0 | 48 | #define COPY8BTOHALF(to, from) COPY8B(to, from, from) |
michael@0 | 49 | #define COPY8BFROMHALF(to, from) COPY8B(to, from, to) |
michael@0 | 50 | |
michael@0 | 51 | static void |
michael@0 | 52 | DES_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
michael@0 | 53 | { |
michael@0 | 54 | while (len) { |
michael@0 | 55 | DES_Do1Block(cx->ks0, in, out); |
michael@0 | 56 | len -= 8; |
michael@0 | 57 | in += 8; |
michael@0 | 58 | out += 8; |
michael@0 | 59 | } |
michael@0 | 60 | } |
michael@0 | 61 | |
michael@0 | 62 | static void |
michael@0 | 63 | DES_EDE3_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
michael@0 | 64 | { |
michael@0 | 65 | while (len) { |
michael@0 | 66 | DES_Do1Block(cx->ks0, in, out); |
michael@0 | 67 | len -= 8; |
michael@0 | 68 | in += 8; |
michael@0 | 69 | DES_Do1Block(cx->ks1, out, out); |
michael@0 | 70 | DES_Do1Block(cx->ks2, out, out); |
michael@0 | 71 | out += 8; |
michael@0 | 72 | } |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | static void |
michael@0 | 76 | DES_CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
michael@0 | 77 | { |
michael@0 | 78 | const BYTE * bufend = in + len; |
michael@0 | 79 | HALF vec[2]; |
michael@0 | 80 | |
michael@0 | 81 | while (in != bufend) { |
michael@0 | 82 | COPY8BTOHALF(vec, in); |
michael@0 | 83 | in += 8; |
michael@0 | 84 | vec[0] ^= cx->iv[0]; |
michael@0 | 85 | vec[1] ^= cx->iv[1]; |
michael@0 | 86 | DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv); |
michael@0 | 87 | COPY8BFROMHALF(out, cx->iv); |
michael@0 | 88 | out += 8; |
michael@0 | 89 | } |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | static void |
michael@0 | 93 | DES_CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
michael@0 | 94 | { |
michael@0 | 95 | const BYTE * bufend; |
michael@0 | 96 | HALF oldciphertext[2]; |
michael@0 | 97 | HALF plaintext [2]; |
michael@0 | 98 | |
michael@0 | 99 | for (bufend = in + len; in != bufend; ) { |
michael@0 | 100 | oldciphertext[0] = cx->iv[0]; |
michael@0 | 101 | oldciphertext[1] = cx->iv[1]; |
michael@0 | 102 | COPY8BTOHALF(cx->iv, in); |
michael@0 | 103 | in += 8; |
michael@0 | 104 | DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext); |
michael@0 | 105 | plaintext[0] ^= oldciphertext[0]; |
michael@0 | 106 | plaintext[1] ^= oldciphertext[1]; |
michael@0 | 107 | COPY8BFROMHALF(out, plaintext); |
michael@0 | 108 | out += 8; |
michael@0 | 109 | } |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | static void |
michael@0 | 113 | DES_EDE3CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
michael@0 | 114 | { |
michael@0 | 115 | const BYTE * bufend = in + len; |
michael@0 | 116 | HALF vec[2]; |
michael@0 | 117 | |
michael@0 | 118 | while (in != bufend) { |
michael@0 | 119 | COPY8BTOHALF(vec, in); |
michael@0 | 120 | in += 8; |
michael@0 | 121 | vec[0] ^= cx->iv[0]; |
michael@0 | 122 | vec[1] ^= cx->iv[1]; |
michael@0 | 123 | DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv); |
michael@0 | 124 | DES_Do1Block( cx->ks1, (BYTE *)cx->iv, (BYTE *)cx->iv); |
michael@0 | 125 | DES_Do1Block( cx->ks2, (BYTE *)cx->iv, (BYTE *)cx->iv); |
michael@0 | 126 | COPY8BFROMHALF(out, cx->iv); |
michael@0 | 127 | out += 8; |
michael@0 | 128 | } |
michael@0 | 129 | } |
michael@0 | 130 | |
michael@0 | 131 | static void |
michael@0 | 132 | DES_EDE3CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
michael@0 | 133 | { |
michael@0 | 134 | const BYTE * bufend; |
michael@0 | 135 | HALF oldciphertext[2]; |
michael@0 | 136 | HALF plaintext [2]; |
michael@0 | 137 | |
michael@0 | 138 | for (bufend = in + len; in != bufend; ) { |
michael@0 | 139 | oldciphertext[0] = cx->iv[0]; |
michael@0 | 140 | oldciphertext[1] = cx->iv[1]; |
michael@0 | 141 | COPY8BTOHALF(cx->iv, in); |
michael@0 | 142 | in += 8; |
michael@0 | 143 | DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext); |
michael@0 | 144 | DES_Do1Block(cx->ks1, (BYTE *)plaintext, (BYTE *)plaintext); |
michael@0 | 145 | DES_Do1Block(cx->ks2, (BYTE *)plaintext, (BYTE *)plaintext); |
michael@0 | 146 | plaintext[0] ^= oldciphertext[0]; |
michael@0 | 147 | plaintext[1] ^= oldciphertext[1]; |
michael@0 | 148 | COPY8BFROMHALF(out, plaintext); |
michael@0 | 149 | out += 8; |
michael@0 | 150 | } |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | DESContext * |
michael@0 | 154 | DES_AllocateContext(void) |
michael@0 | 155 | { |
michael@0 | 156 | return PORT_ZNew(DESContext); |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | SECStatus |
michael@0 | 160 | DES_InitContext(DESContext *cx, const unsigned char *key, unsigned int keylen, |
michael@0 | 161 | const unsigned char *iv, int mode, unsigned int encrypt, |
michael@0 | 162 | unsigned int unused) |
michael@0 | 163 | { |
michael@0 | 164 | DESDirection opposite; |
michael@0 | 165 | if (!cx) { |
michael@0 | 166 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 167 | return SECFailure; |
michael@0 | 168 | } |
michael@0 | 169 | cx->direction = encrypt ? DES_ENCRYPT : DES_DECRYPT; |
michael@0 | 170 | opposite = encrypt ? DES_DECRYPT : DES_ENCRYPT; |
michael@0 | 171 | switch (mode) { |
michael@0 | 172 | case NSS_DES: /* DES ECB */ |
michael@0 | 173 | DES_MakeSchedule( cx->ks0, key, cx->direction); |
michael@0 | 174 | cx->worker = &DES_ECB; |
michael@0 | 175 | break; |
michael@0 | 176 | |
michael@0 | 177 | case NSS_DES_EDE3: /* DES EDE ECB */ |
michael@0 | 178 | cx->worker = &DES_EDE3_ECB; |
michael@0 | 179 | if (encrypt) { |
michael@0 | 180 | DES_MakeSchedule(cx->ks0, key, cx->direction); |
michael@0 | 181 | DES_MakeSchedule(cx->ks1, key + 8, opposite); |
michael@0 | 182 | DES_MakeSchedule(cx->ks2, key + 16, cx->direction); |
michael@0 | 183 | } else { |
michael@0 | 184 | DES_MakeSchedule(cx->ks2, key, cx->direction); |
michael@0 | 185 | DES_MakeSchedule(cx->ks1, key + 8, opposite); |
michael@0 | 186 | DES_MakeSchedule(cx->ks0, key + 16, cx->direction); |
michael@0 | 187 | } |
michael@0 | 188 | break; |
michael@0 | 189 | |
michael@0 | 190 | case NSS_DES_CBC: /* DES CBC */ |
michael@0 | 191 | COPY8BTOHALF(cx->iv, iv); |
michael@0 | 192 | cx->worker = encrypt ? &DES_CBCEn : &DES_CBCDe; |
michael@0 | 193 | DES_MakeSchedule(cx->ks0, key, cx->direction); |
michael@0 | 194 | break; |
michael@0 | 195 | |
michael@0 | 196 | case NSS_DES_EDE3_CBC: /* DES EDE CBC */ |
michael@0 | 197 | COPY8BTOHALF(cx->iv, iv); |
michael@0 | 198 | if (encrypt) { |
michael@0 | 199 | cx->worker = &DES_EDE3CBCEn; |
michael@0 | 200 | DES_MakeSchedule(cx->ks0, key, cx->direction); |
michael@0 | 201 | DES_MakeSchedule(cx->ks1, key + 8, opposite); |
michael@0 | 202 | DES_MakeSchedule(cx->ks2, key + 16, cx->direction); |
michael@0 | 203 | } else { |
michael@0 | 204 | cx->worker = &DES_EDE3CBCDe; |
michael@0 | 205 | DES_MakeSchedule(cx->ks2, key, cx->direction); |
michael@0 | 206 | DES_MakeSchedule(cx->ks1, key + 8, opposite); |
michael@0 | 207 | DES_MakeSchedule(cx->ks0, key + 16, cx->direction); |
michael@0 | 208 | } |
michael@0 | 209 | break; |
michael@0 | 210 | |
michael@0 | 211 | default: |
michael@0 | 212 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 213 | return SECFailure; |
michael@0 | 214 | } |
michael@0 | 215 | return SECSuccess; |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | DESContext * |
michael@0 | 219 | DES_CreateContext(const BYTE * key, const BYTE *iv, int mode, PRBool encrypt) |
michael@0 | 220 | { |
michael@0 | 221 | DESContext *cx = PORT_ZNew(DESContext); |
michael@0 | 222 | SECStatus rv = DES_InitContext(cx, key, 0, iv, mode, encrypt, 0); |
michael@0 | 223 | |
michael@0 | 224 | if (rv != SECSuccess) { |
michael@0 | 225 | PORT_ZFree(cx, sizeof *cx); |
michael@0 | 226 | cx = NULL; |
michael@0 | 227 | } |
michael@0 | 228 | return cx; |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | void |
michael@0 | 232 | DES_DestroyContext(DESContext *cx, PRBool freeit) |
michael@0 | 233 | { |
michael@0 | 234 | if (cx) { |
michael@0 | 235 | memset(cx, 0, sizeof *cx); |
michael@0 | 236 | if (freeit) |
michael@0 | 237 | PORT_Free(cx); |
michael@0 | 238 | } |
michael@0 | 239 | } |
michael@0 | 240 | |
michael@0 | 241 | SECStatus |
michael@0 | 242 | DES_Encrypt(DESContext *cx, BYTE *out, unsigned int *outLen, |
michael@0 | 243 | unsigned int maxOutLen, const BYTE *in, unsigned int inLen) |
michael@0 | 244 | { |
michael@0 | 245 | |
michael@0 | 246 | if ((inLen % 8) != 0 || maxOutLen < inLen || !cx || |
michael@0 | 247 | cx->direction != DES_ENCRYPT) { |
michael@0 | 248 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 249 | return SECFailure; |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | cx->worker(cx, out, in, inLen); |
michael@0 | 253 | if (outLen) |
michael@0 | 254 | *outLen = inLen; |
michael@0 | 255 | return SECSuccess; |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | SECStatus |
michael@0 | 259 | DES_Decrypt(DESContext *cx, BYTE *out, unsigned int *outLen, |
michael@0 | 260 | unsigned int maxOutLen, const BYTE *in, unsigned int inLen) |
michael@0 | 261 | { |
michael@0 | 262 | |
michael@0 | 263 | if ((inLen % 8) != 0 || maxOutLen < inLen || !cx || |
michael@0 | 264 | cx->direction != DES_DECRYPT) { |
michael@0 | 265 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 266 | return SECFailure; |
michael@0 | 267 | } |
michael@0 | 268 | |
michael@0 | 269 | cx->worker(cx, out, in, inLen); |
michael@0 | 270 | if (outLen) |
michael@0 | 271 | *outLen = inLen; |
michael@0 | 272 | return SECSuccess; |
michael@0 | 273 | } |