sha256.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 23 Jun 2017 17:28:03 -0400
changeset 58 1390348facc7
parent 46 fe4f59680246
permissions -rw-r--r--
Command line tool that decrypts an OPVault keychain and dumps it to stdout.

To compile: gcc -o opvault opvault.c cJSON.c -lcrypto

Usage: ./opvault </path/to/mykeychain.opvault> <password>

This is just a proof of concept; I'll be recycling this into proper OPVault
support in 1pass later and deleting this tool.

This uses OpenSSL's libcrypto for the math instead of all the homegrown
crypto this project is otherwise using. I'll probably migrate the rest in
this direction, too, since this wasn't as bad as I expected to use and
gets you all the package-manager mojo of automatic bug fixes and security
patches and shared code, etc.

cJSON parses JSON in C. That is from https://github.com/DaveGamble/cJSON

An example OPVault keychain from AgileBits is available here:

https://cache.agilebits.com/security-kb/
icculus@46
     1
/*********************************************************************
icculus@46
     2
* Filename:   sha256.c
icculus@46
     3
* Author:     Brad Conte (brad AT bradconte.com)
icculus@46
     4
* Copyright:
icculus@46
     5
* Disclaimer: This code is presented "as is" without any guarantees.
icculus@46
     6
* Details:    Implementation of the SHA-256 hashing algorithm.
icculus@46
     7
              SHA-256 is one of the three algorithms in the SHA2
icculus@46
     8
              specification. The others, SHA-384 and SHA-512, are not
icculus@46
     9
              offered in this implementation.
icculus@46
    10
              Algorithm specification can be found here:
icculus@46
    11
               * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
icculus@46
    12
              This implementation uses little endian byte order.
icculus@46
    13
*********************************************************************/
icculus@46
    14
icculus@46
    15
/*************************** HEADER FILES ***************************/
icculus@46
    16
#include <stdlib.h>
icculus@46
    17
#include <memory.h>
icculus@46
    18
#include "sha256.h"
icculus@46
    19
icculus@46
    20
/****************************** MACROS ******************************/
icculus@46
    21
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
icculus@46
    22
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
icculus@46
    23
icculus@46
    24
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
icculus@46
    25
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
icculus@46
    26
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
icculus@46
    27
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
icculus@46
    28
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
icculus@46
    29
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
icculus@46
    30
icculus@46
    31
/**************************** VARIABLES *****************************/
icculus@46
    32
static const WORD k[64] = {
icculus@46
    33
	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
icculus@46
    34
	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
icculus@46
    35
	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
icculus@46
    36
	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
icculus@46
    37
	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
icculus@46
    38
	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
icculus@46
    39
	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
icculus@46
    40
	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
icculus@46
    41
};
icculus@46
    42
icculus@46
    43
/*********************** FUNCTION DEFINITIONS ***********************/
icculus@46
    44
void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
icculus@46
    45
{
icculus@46
    46
	WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
icculus@46
    47
icculus@46
    48
	for (i = 0, j = 0; i < 16; ++i, j += 4)
icculus@46
    49
		m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
icculus@46
    50
	for ( ; i < 64; ++i)
icculus@46
    51
		m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
icculus@46
    52
icculus@46
    53
	a = ctx->state[0];
icculus@46
    54
	b = ctx->state[1];
icculus@46
    55
	c = ctx->state[2];
icculus@46
    56
	d = ctx->state[3];
icculus@46
    57
	e = ctx->state[4];
icculus@46
    58
	f = ctx->state[5];
icculus@46
    59
	g = ctx->state[6];
icculus@46
    60
	h = ctx->state[7];
icculus@46
    61
icculus@46
    62
	for (i = 0; i < 64; ++i) {
icculus@46
    63
		t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
icculus@46
    64
		t2 = EP0(a) + MAJ(a,b,c);
icculus@46
    65
		h = g;
icculus@46
    66
		g = f;
icculus@46
    67
		f = e;
icculus@46
    68
		e = d + t1;
icculus@46
    69
		d = c;
icculus@46
    70
		c = b;
icculus@46
    71
		b = a;
icculus@46
    72
		a = t1 + t2;
icculus@46
    73
	}
icculus@46
    74
icculus@46
    75
	ctx->state[0] += a;
icculus@46
    76
	ctx->state[1] += b;
icculus@46
    77
	ctx->state[2] += c;
icculus@46
    78
	ctx->state[3] += d;
icculus@46
    79
	ctx->state[4] += e;
icculus@46
    80
	ctx->state[5] += f;
icculus@46
    81
	ctx->state[6] += g;
icculus@46
    82
	ctx->state[7] += h;
icculus@46
    83
}
icculus@46
    84
icculus@46
    85
void sha256_init(SHA256_CTX *ctx)
icculus@46
    86
{
icculus@46
    87
	ctx->datalen = 0;
icculus@46
    88
	ctx->bitlen = 0;
icculus@46
    89
	ctx->state[0] = 0x6a09e667;
icculus@46
    90
	ctx->state[1] = 0xbb67ae85;
icculus@46
    91
	ctx->state[2] = 0x3c6ef372;
icculus@46
    92
	ctx->state[3] = 0xa54ff53a;
icculus@46
    93
	ctx->state[4] = 0x510e527f;
icculus@46
    94
	ctx->state[5] = 0x9b05688c;
icculus@46
    95
	ctx->state[6] = 0x1f83d9ab;
icculus@46
    96
	ctx->state[7] = 0x5be0cd19;
icculus@46
    97
}
icculus@46
    98
icculus@46
    99
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
icculus@46
   100
{
icculus@46
   101
	WORD i;
icculus@46
   102
icculus@46
   103
	for (i = 0; i < len; ++i) {
icculus@46
   104
		ctx->data[ctx->datalen] = data[i];
icculus@46
   105
		ctx->datalen++;
icculus@46
   106
		if (ctx->datalen == 64) {
icculus@46
   107
			sha256_transform(ctx, ctx->data);
icculus@46
   108
			ctx->bitlen += 512;
icculus@46
   109
			ctx->datalen = 0;
icculus@46
   110
		}
icculus@46
   111
	}
icculus@46
   112
}
icculus@46
   113
icculus@46
   114
void sha256_final(SHA256_CTX *ctx, BYTE hash[])
icculus@46
   115
{
icculus@46
   116
	WORD i;
icculus@46
   117
icculus@46
   118
	i = ctx->datalen;
icculus@46
   119
icculus@46
   120
	// Pad whatever data is left in the buffer.
icculus@46
   121
	if (ctx->datalen < 56) {
icculus@46
   122
		ctx->data[i++] = 0x80;
icculus@46
   123
		while (i < 56)
icculus@46
   124
			ctx->data[i++] = 0x00;
icculus@46
   125
	}
icculus@46
   126
	else {
icculus@46
   127
		ctx->data[i++] = 0x80;
icculus@46
   128
		while (i < 64)
icculus@46
   129
			ctx->data[i++] = 0x00;
icculus@46
   130
		sha256_transform(ctx, ctx->data);
icculus@46
   131
		memset(ctx->data, 0, 56);
icculus@46
   132
	}
icculus@46
   133
icculus@46
   134
	// Append to the padding the total message's length in bits and transform.
icculus@46
   135
	ctx->bitlen += ctx->datalen * 8;
icculus@46
   136
	ctx->data[63] = ctx->bitlen;
icculus@46
   137
	ctx->data[62] = ctx->bitlen >> 8;
icculus@46
   138
	ctx->data[61] = ctx->bitlen >> 16;
icculus@46
   139
	ctx->data[60] = ctx->bitlen >> 24;
icculus@46
   140
	ctx->data[59] = ctx->bitlen >> 32;
icculus@46
   141
	ctx->data[58] = ctx->bitlen >> 40;
icculus@46
   142
	ctx->data[57] = ctx->bitlen >> 48;
icculus@46
   143
	ctx->data[56] = ctx->bitlen >> 56;
icculus@46
   144
	sha256_transform(ctx, ctx->data);
icculus@46
   145
icculus@46
   146
	// Since this implementation uses little endian byte ordering and SHA uses big endian,
icculus@46
   147
	// reverse all the bytes when copying the final state to the output hash.
icculus@46
   148
	for (i = 0; i < 4; ++i) {
icculus@46
   149
		hash[i]      = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
icculus@46
   150
		hash[i + 4]  = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
icculus@46
   151
		hash[i + 8]  = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
icculus@46
   152
		hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
icculus@46
   153
		hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
icculus@46
   154
		hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
icculus@46
   155
		hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
icculus@46
   156
		hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
icculus@46
   157
	}
icculus@46
   158
}