| 1 /* |
|
| 2 * purple |
|
| 3 * |
|
| 4 * Purple is the legal property of its developers, whose names are too numerous |
|
| 5 * to list here. Please refer to the COPYRIGHT file distributed with this |
|
| 6 * source distribution. |
|
| 7 * |
|
| 8 * This program is free software; you can redistribute it and/or modify |
|
| 9 * it under the terms of the GNU General Public License as published by |
|
| 10 * the Free Software Foundation; either version 2 of the License, or |
|
| 11 * (at your option) any later version. |
|
| 12 * |
|
| 13 * This program is distributed in the hope that it will be useful, |
|
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 * GNU General Public License for more details. |
|
| 17 * |
|
| 18 * You should have received a copy of the GNU General Public License |
|
| 19 * along with this program; if not, write to the Free Software |
|
| 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
|
| 21 */ |
|
| 22 #include <cipher.h> |
|
| 23 |
|
| 24 #if !GLIB_CHECK_VERSION(2,16,0) |
|
| 25 |
|
| 26 #define SHA256_HMAC_BLOCK_SIZE 64 |
|
| 27 #define SHA256_ROTR(X,n) ((((X) >> (n)) | ((X) << (32-(n)))) & 0xFFFFFFFF) |
|
| 28 |
|
| 29 static const guint32 sha256_K[64] = |
|
| 30 { |
|
| 31 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, |
|
| 32 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, |
|
| 33 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, |
|
| 34 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, |
|
| 35 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, |
|
| 36 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, |
|
| 37 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, |
|
| 38 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 |
|
| 39 }; |
|
| 40 |
|
| 41 struct SHA256Context { |
|
| 42 guint32 H[8]; |
|
| 43 guint32 W[64]; |
|
| 44 |
|
| 45 gint lenW; |
|
| 46 |
|
| 47 guint32 sizeHi; |
|
| 48 guint32 sizeLo; |
|
| 49 }; |
|
| 50 |
|
| 51 static size_t |
|
| 52 sha256_get_block_size(PurpleCipherContext *context) |
|
| 53 { |
|
| 54 /* This does not change (in this case) */ |
|
| 55 return SHA256_HMAC_BLOCK_SIZE; |
|
| 56 } |
|
| 57 |
|
| 58 static void |
|
| 59 sha256_hash_block(struct SHA256Context *sha256_ctx) { |
|
| 60 gint i; |
|
| 61 guint32 A, B, C, D, E, F, G, H, T1, T2; |
|
| 62 |
|
| 63 for(i = 16; i < 64; i++) { |
|
| 64 sha256_ctx->W[i] = |
|
| 65 (SHA256_ROTR(sha256_ctx->W[i-2], 17) ^ SHA256_ROTR(sha256_ctx->W[i-2], 19) ^ (sha256_ctx->W[i-2] >> 10)) |
|
| 66 + sha256_ctx->W[i-7] |
|
| 67 + (SHA256_ROTR(sha256_ctx->W[i-15], 7) ^ SHA256_ROTR(sha256_ctx->W[i-15], 18) ^ (sha256_ctx->W[i-15] >> 3)) |
|
| 68 + sha256_ctx->W[i-16]; |
|
| 69 } |
|
| 70 |
|
| 71 A = sha256_ctx->H[0]; |
|
| 72 B = sha256_ctx->H[1]; |
|
| 73 C = sha256_ctx->H[2]; |
|
| 74 D = sha256_ctx->H[3]; |
|
| 75 E = sha256_ctx->H[4]; |
|
| 76 F = sha256_ctx->H[5]; |
|
| 77 G = sha256_ctx->H[6]; |
|
| 78 H = sha256_ctx->H[7]; |
|
| 79 |
|
| 80 for(i = 0; i < 64; i++) { |
|
| 81 T1 = H |
|
| 82 + (SHA256_ROTR(E, 6) ^ SHA256_ROTR(E, 11) ^ SHA256_ROTR(E, 25)) |
|
| 83 + ((E & F) ^ ((~E) & G)) |
|
| 84 + sha256_K[i] + sha256_ctx->W[i]; |
|
| 85 T2 = (SHA256_ROTR(A, 2) ^ SHA256_ROTR(A, 13) ^ SHA256_ROTR(A, 22)) |
|
| 86 + ((A & B) ^ (A & C) ^ (B & C)); |
|
| 87 H = G; |
|
| 88 G = F; |
|
| 89 F = E; |
|
| 90 E = D + T1; |
|
| 91 D = C; |
|
| 92 C = B; |
|
| 93 B = A; |
|
| 94 A = T1 + T2; |
|
| 95 } |
|
| 96 |
|
| 97 sha256_ctx->H[0] += A; |
|
| 98 sha256_ctx->H[1] += B; |
|
| 99 sha256_ctx->H[2] += C; |
|
| 100 sha256_ctx->H[3] += D; |
|
| 101 sha256_ctx->H[4] += E; |
|
| 102 sha256_ctx->H[5] += F; |
|
| 103 sha256_ctx->H[6] += G; |
|
| 104 sha256_ctx->H[7] += H; |
|
| 105 } |
|
| 106 |
|
| 107 static void |
|
| 108 sha256_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { |
|
| 109 struct SHA256Context *ctx; |
|
| 110 |
|
| 111 ctx = purple_cipher_context_get_data(context); |
|
| 112 |
|
| 113 if(!strcmp(name, "sizeHi")) { |
|
| 114 ctx->sizeHi = GPOINTER_TO_INT(value); |
|
| 115 } else if(!strcmp(name, "sizeLo")) { |
|
| 116 ctx->sizeLo = GPOINTER_TO_INT(value); |
|
| 117 } else if(!strcmp(name, "lenW")) { |
|
| 118 ctx->lenW = GPOINTER_TO_INT(value); |
|
| 119 } |
|
| 120 } |
|
| 121 |
|
| 122 static void * |
|
| 123 sha256_get_opt(PurpleCipherContext *context, const gchar *name) { |
|
| 124 struct SHA256Context *ctx; |
|
| 125 |
|
| 126 ctx = purple_cipher_context_get_data(context); |
|
| 127 |
|
| 128 if(!strcmp(name, "sizeHi")) { |
|
| 129 return GINT_TO_POINTER(ctx->sizeHi); |
|
| 130 } else if(!strcmp(name, "sizeLo")) { |
|
| 131 return GINT_TO_POINTER(ctx->sizeLo); |
|
| 132 } else if(!strcmp(name, "lenW")) { |
|
| 133 return GINT_TO_POINTER(ctx->lenW); |
|
| 134 } |
|
| 135 |
|
| 136 return NULL; |
|
| 137 } |
|
| 138 |
|
| 139 static void |
|
| 140 sha256_init(PurpleCipherContext *context, void *extra) { |
|
| 141 struct SHA256Context *sha256_ctx; |
|
| 142 |
|
| 143 sha256_ctx = g_new0(struct SHA256Context, 1); |
|
| 144 |
|
| 145 purple_cipher_context_set_data(context, sha256_ctx); |
|
| 146 |
|
| 147 purple_cipher_context_reset(context, extra); |
|
| 148 } |
|
| 149 |
|
| 150 static void |
|
| 151 sha256_reset(PurpleCipherContext *context, void *extra) { |
|
| 152 struct SHA256Context *sha256_ctx; |
|
| 153 gint i; |
|
| 154 |
|
| 155 sha256_ctx = purple_cipher_context_get_data(context); |
|
| 156 |
|
| 157 g_return_if_fail(sha256_ctx); |
|
| 158 |
|
| 159 sha256_ctx->lenW = 0; |
|
| 160 sha256_ctx->sizeHi = 0; |
|
| 161 sha256_ctx->sizeLo = 0; |
|
| 162 |
|
| 163 sha256_ctx->H[0] = 0x6a09e667; |
|
| 164 sha256_ctx->H[1] = 0xbb67ae85; |
|
| 165 sha256_ctx->H[2] = 0x3c6ef372; |
|
| 166 sha256_ctx->H[3] = 0xa54ff53a; |
|
| 167 sha256_ctx->H[4] = 0x510e527f; |
|
| 168 sha256_ctx->H[5] = 0x9b05688c; |
|
| 169 sha256_ctx->H[6] = 0x1f83d9ab; |
|
| 170 sha256_ctx->H[7] = 0x5be0cd19; |
|
| 171 |
|
| 172 for(i = 0; i < 64; i++) |
|
| 173 sha256_ctx->W[i] = 0; |
|
| 174 } |
|
| 175 |
|
| 176 static void |
|
| 177 sha256_uninit(PurpleCipherContext *context) { |
|
| 178 struct SHA256Context *sha256_ctx; |
|
| 179 |
|
| 180 purple_cipher_context_reset(context, NULL); |
|
| 181 |
|
| 182 sha256_ctx = purple_cipher_context_get_data(context); |
|
| 183 |
|
| 184 memset(sha256_ctx, 0, sizeof(struct SHA256Context)); |
|
| 185 |
|
| 186 g_free(sha256_ctx); |
|
| 187 sha256_ctx = NULL; |
|
| 188 } |
|
| 189 |
|
| 190 static void |
|
| 191 sha256_append(PurpleCipherContext *context, const guchar *data, size_t len) { |
|
| 192 struct SHA256Context *sha256_ctx; |
|
| 193 gint i; |
|
| 194 |
|
| 195 sha256_ctx = purple_cipher_context_get_data(context); |
|
| 196 |
|
| 197 g_return_if_fail(sha256_ctx); |
|
| 198 |
|
| 199 for(i = 0; i < len; i++) { |
|
| 200 sha256_ctx->W[sha256_ctx->lenW / 4] <<= 8; |
|
| 201 sha256_ctx->W[sha256_ctx->lenW / 4] |= data[i]; |
|
| 202 |
|
| 203 if((++sha256_ctx->lenW) % 64 == 0) { |
|
| 204 sha256_hash_block(sha256_ctx); |
|
| 205 sha256_ctx->lenW = 0; |
|
| 206 } |
|
| 207 |
|
| 208 sha256_ctx->sizeLo += 8; |
|
| 209 sha256_ctx->sizeHi += (sha256_ctx->sizeLo < 8); |
|
| 210 } |
|
| 211 } |
|
| 212 |
|
| 213 static gboolean |
|
| 214 sha256_digest(PurpleCipherContext *context, size_t in_len, guchar digest[32], |
|
| 215 size_t *out_len) |
|
| 216 { |
|
| 217 struct SHA256Context *sha256_ctx; |
|
| 218 guchar pad0x80 = 0x80, pad0x00 = 0x00; |
|
| 219 guchar padlen[8]; |
|
| 220 gint i; |
|
| 221 |
|
| 222 g_return_val_if_fail(in_len >= 32, FALSE); |
|
| 223 |
|
| 224 sha256_ctx = purple_cipher_context_get_data(context); |
|
| 225 |
|
| 226 g_return_val_if_fail(sha256_ctx, FALSE); |
|
| 227 |
|
| 228 padlen[0] = (guchar)((sha256_ctx->sizeHi >> 24) & 255); |
|
| 229 padlen[1] = (guchar)((sha256_ctx->sizeHi >> 16) & 255); |
|
| 230 padlen[2] = (guchar)((sha256_ctx->sizeHi >> 8) & 255); |
|
| 231 padlen[3] = (guchar)((sha256_ctx->sizeHi >> 0) & 255); |
|
| 232 padlen[4] = (guchar)((sha256_ctx->sizeLo >> 24) & 255); |
|
| 233 padlen[5] = (guchar)((sha256_ctx->sizeLo >> 16) & 255); |
|
| 234 padlen[6] = (guchar)((sha256_ctx->sizeLo >> 8) & 255); |
|
| 235 padlen[7] = (guchar)((sha256_ctx->sizeLo >> 0) & 255); |
|
| 236 |
|
| 237 /* pad with a 1, then zeroes, then length */ |
|
| 238 purple_cipher_context_append(context, &pad0x80, 1); |
|
| 239 while(sha256_ctx->lenW != 56) |
|
| 240 purple_cipher_context_append(context, &pad0x00, 1); |
|
| 241 purple_cipher_context_append(context, padlen, 8); |
|
| 242 |
|
| 243 for(i = 0; i < 32; i++) { |
|
| 244 digest[i] = (guchar)(sha256_ctx->H[i / 4] >> 24); |
|
| 245 sha256_ctx->H[i / 4] <<= 8; |
|
| 246 } |
|
| 247 |
|
| 248 purple_cipher_context_reset(context, NULL); |
|
| 249 |
|
| 250 if(out_len) |
|
| 251 *out_len = 32; |
|
| 252 |
|
| 253 return TRUE; |
|
| 254 } |
|
| 255 |
|
| 256 static PurpleCipherOps SHA256Ops = { |
|
| 257 sha256_set_opt, /* Set Option */ |
|
| 258 sha256_get_opt, /* Get Option */ |
|
| 259 sha256_init, /* init */ |
|
| 260 sha256_reset, /* reset */ |
|
| 261 sha256_uninit, /* uninit */ |
|
| 262 NULL, /* set iv */ |
|
| 263 sha256_append, /* append */ |
|
| 264 sha256_digest, /* digest */ |
|
| 265 NULL, /* encrypt */ |
|
| 266 NULL, /* decrypt */ |
|
| 267 NULL, /* set salt */ |
|
| 268 NULL, /* get salt size */ |
|
| 269 NULL, /* set key */ |
|
| 270 NULL, /* get key size */ |
|
| 271 NULL, /* set batch mode */ |
|
| 272 NULL, /* get batch mode */ |
|
| 273 sha256_get_block_size, /* get block size */ |
|
| 274 NULL /* set key with len */ |
|
| 275 }; |
|
| 276 |
|
| 277 PurpleCipherOps * |
|
| 278 purple_sha256_cipher_get_ops(void) { |
|
| 279 return &SHA256Ops; |
|
| 280 } |
|
| 281 |
|
| 282 #endif /* !GLIB_CHECK_VERSION(2,16,0) */ |
|
| 283 |
|