sha1.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 23 Jun 2017 17:28:03 -0400
changeset 58 1390348facc7
parent 53 ea43dbad123b
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@0
     1
/*	$OpenBSD: sha1.c,v 1.9 2011/01/11 15:50:40 deraadt Exp $	*/
icculus@0
     2
icculus@0
     3
/*
icculus@0
     4
 * SHA-1 in C
icculus@0
     5
 * By Steve Reid <steve@edmweb.com>
icculus@0
     6
 * 100% Public Domain
icculus@0
     7
 * 
icculus@0
     8
 * Test Vectors (from FIPS PUB 180-1)
icculus@0
     9
 * "abc"
icculus@0
    10
 *   A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
icculus@0
    11
 * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
icculus@0
    12
 *   84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
icculus@0
    13
 * A million repetitions of "a"
icculus@0
    14
 *   34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
icculus@0
    15
*/
icculus@0
    16
icculus@0
    17
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
icculus@0
    18
/* #define SHA1HANDSOFF * Copies data before messing with it. */
icculus@0
    19
icculus@0
    20
#define SHA1HANDSOFF
icculus@0
    21
icculus@0
    22
#include <string.h>
icculus@0
    23
#include <sys/param.h>
icculus@0
    24
//#include <sys/systm.h>
icculus@0
    25
icculus@0
    26
#include "sha1.h"
icculus@0
    27
icculus@0
    28
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
icculus@0
    29
icculus@0
    30
/* blk0() and blk() perform the initial expand. */
icculus@0
    31
/* I got the idea of expanding during the round function from SSLeay */
icculus@0
    32
#if PLATFORM_LITTLEENDIAN
icculus@0
    33
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
icculus@0
    34
    |(rol(block->l[i],8)&0x00FF00FF))
icculus@0
    35
#else
icculus@0
    36
#define blk0(i) block->l[i]
icculus@0
    37
#endif
icculus@0
    38
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
icculus@0
    39
    ^block->l[(i+2)&15]^block->l[i&15],1))
icculus@0
    40
icculus@0
    41
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
icculus@0
    42
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
icculus@0
    43
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
icculus@0
    44
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
icculus@0
    45
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
icculus@0
    46
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
icculus@0
    47
icculus@0
    48
/* Hash a single 512-bit block. This is the core of the algorithm. */
icculus@0
    49
icculus@0
    50
void
icculus@52
    51
SHA1Transform(uint32_t state[5], const uint8_t buffer[SHA1_BLOCK_LENGTH])
icculus@0
    52
{
icculus@52
    53
    uint32_t a, b, c, d, e;
icculus@0
    54
    typedef union {
icculus@52
    55
        uint8_t c[64];
icculus@52
    56
        uint32_t l[16];
icculus@0
    57
    } CHAR64LONG16;
icculus@0
    58
    CHAR64LONG16* block;
icculus@0
    59
#ifdef SHA1HANDSOFF
icculus@52
    60
    uint8_t workspace[SHA1_BLOCK_LENGTH];
icculus@0
    61
icculus@0
    62
    block = (CHAR64LONG16 *)workspace;
icculus@0
    63
    memcpy(block, buffer, SHA1_BLOCK_LENGTH);
icculus@0
    64
#else
icculus@0
    65
    block = (CHAR64LONG16 *)buffer;
icculus@0
    66
#endif
icculus@0
    67
    /* Copy context->state[] to working vars */
icculus@0
    68
    a = state[0];
icculus@0
    69
    b = state[1];
icculus@0
    70
    c = state[2];
icculus@0
    71
    d = state[3];
icculus@0
    72
    e = state[4];
icculus@0
    73
icculus@0
    74
    /* 4 rounds of 20 operations each. Loop unrolled. */
icculus@0
    75
    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
icculus@0
    76
    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
icculus@0
    77
    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
icculus@0
    78
    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
icculus@0
    79
    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
icculus@0
    80
    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
icculus@0
    81
    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
icculus@0
    82
    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
icculus@0
    83
    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
icculus@0
    84
    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
icculus@0
    85
    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
icculus@0
    86
    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
icculus@0
    87
    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
icculus@0
    88
    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
icculus@0
    89
    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
icculus@0
    90
    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
icculus@0
    91
    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
icculus@0
    92
    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
icculus@0
    93
    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
icculus@0
    94
    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
icculus@0
    95
icculus@0
    96
    /* Add the working vars back into context.state[] */
icculus@0
    97
    state[0] += a;
icculus@0
    98
    state[1] += b;
icculus@0
    99
    state[2] += c;
icculus@0
   100
    state[3] += d;
icculus@0
   101
    state[4] += e;
icculus@0
   102
    /* Wipe variables */
icculus@0
   103
    a = b = c = d = e = 0;
icculus@0
   104
}
icculus@0
   105
icculus@0
   106
icculus@0
   107
/* SHA1Init - Initialize new context */
icculus@0
   108
icculus@0
   109
void
icculus@0
   110
SHA1Init(SHA1_CTX *context)
icculus@0
   111
{
icculus@0
   112
    /* SHA1 initialization constants */
icculus@0
   113
    context->count = 0;
icculus@0
   114
    context->state[0] = 0x67452301;
icculus@0
   115
    context->state[1] = 0xEFCDAB89;
icculus@0
   116
    context->state[2] = 0x98BADCFE;
icculus@0
   117
    context->state[3] = 0x10325476;
icculus@0
   118
    context->state[4] = 0xC3D2E1F0;
icculus@0
   119
}
icculus@0
   120
icculus@0
   121
icculus@0
   122
/* Run your data through this. */
icculus@0
   123
icculus@0
   124
void
icculus@52
   125
SHA1Update(SHA1_CTX *context, const uint8_t *data, const uint32_t len)
icculus@0
   126
{
icculus@52
   127
    uint32_t i;
icculus@52
   128
    uint32_t j;
icculus@0
   129
icculus@52
   130
    j = (uint32_t)((context->count >> 3) & 63);
icculus@0
   131
    context->count += (len << 3);
icculus@0
   132
    if ((j + len) > 63) {
icculus@0
   133
        memcpy(&context->buffer[j], data, (i = 64 - j));
icculus@0
   134
        SHA1Transform(context->state, context->buffer);
icculus@0
   135
        for ( ; i + 63 < len; i += 64) {
icculus@0
   136
            SHA1Transform(context->state, &data[i]);
icculus@0
   137
        }
icculus@0
   138
        j = 0;
icculus@0
   139
    }
icculus@0
   140
    else i = 0;
icculus@0
   141
    memcpy(&context->buffer[j], &data[i], len - i);
icculus@0
   142
}
icculus@0
   143
icculus@0
   144
icculus@0
   145
/* Add padding and return the message digest. */
icculus@0
   146
icculus@0
   147
void
icculus@52
   148
SHA1Final(uint8_t digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context)
icculus@0
   149
{
icculus@0
   150
    unsigned int i;
icculus@52
   151
    uint8_t finalcount[8];
icculus@0
   152
icculus@0
   153
    for (i = 0; i < 8; i++) {
icculus@52
   154
        finalcount[i] = (uint8_t)((context->count >>
icculus@0
   155
            ((7 - (i & 7)) * 8)) & 255);  /* Endian independent */
icculus@0
   156
    }
icculus@52
   157
    SHA1Update(context, (uint8_t *)"\200", 1);
icculus@0
   158
    while ((context->count & 504) != 448) {
icculus@52
   159
        SHA1Update(context, (uint8_t *)"\0", 1);
icculus@0
   160
    }
icculus@0
   161
    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
icculus@0
   162
icculus@0
   163
    if (digest)
icculus@0
   164
        for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
icculus@52
   165
            digest[i] = (uint8_t)((context->state[i >> 2] >>
icculus@0
   166
                ((3 - (i & 3)) * 8)) & 255);
icculus@0
   167
      }
icculus@0
   168
    memset(finalcount, '\0', 8);
icculus@0
   169
#if 0	/* We want to use this for "keyfill" */
icculus@0
   170
    /* Wipe variables */
icculus@0
   171
    i = 0;
icculus@0
   172
    bzero(context->buffer, 64);
icculus@0
   173
    bzero(context->state, 20);
icculus@0
   174
    bzero(context->count, 8);
icculus@0
   175
#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite its own static vars */
icculus@0
   176
    SHA1Transform(context->state, context->buffer);
icculus@0
   177
#endif
icculus@0
   178
#endif
icculus@0
   179
}
icculus@53
   180
icculus@53
   181
icculus@53
   182
/* https://www.ietf.org/rfc/rfc2104.txt */
icculus@53
   183
void SHA1Hmac(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t digest[SHA1_DIGEST_LENGTH])
icculus@53
   184
{
icculus@53
   185
    SHA1_CTX sha1;
icculus@53
   186
    uint8_t block[64];  // 512 bits.
icculus@53
   187
    uint8_t xori[sizeof (block)];
icculus@53
   188
    uint8_t xoro[sizeof (block)];
icculus@53
   189
    int i;
icculus@53
   190
icculus@53
   191
    memset(block, '\0', sizeof (block));
icculus@53
   192
    if (keylen <= sizeof (block)) {
icculus@53
   193
        memcpy(block, key, keylen);
icculus@53
   194
    } else {
icculus@53
   195
        /* SHA-1 the key itself to shrink it down. */
icculus@53
   196
        SHA1Init(&sha1);
icculus@53
   197
        SHA1Update(&sha1, key, keylen);
icculus@53
   198
        SHA1Final(block, &sha1);
icculus@53
   199
    }
icculus@53
   200
icculus@53
   201
    for (i = 0; i < sizeof (block); i++) {
icculus@53
   202
        const uint8_t b = block[i];
icculus@53
   203
        xori[i] = b ^ 0x36;  /* XOR block vs ipad value */
icculus@53
   204
        xoro[i] = b ^ 0x5C;  /* XOR block vs opad value */
icculus@53
   205
    }
icculus@53
   206
icculus@53
   207
    SHA1Init(&sha1);
icculus@53
   208
    SHA1Update(&sha1, xori, sizeof (xori));
icculus@53
   209
    SHA1Update(&sha1, msg, msglen);
icculus@53
   210
    SHA1Final(block, &sha1);
icculus@53
   211
icculus@53
   212
    SHA1Init(&sha1);
icculus@53
   213
    SHA1Update(&sha1, xoro, sizeof (xoro));
icculus@53
   214
    SHA1Update(&sha1, block, SHA1_DIGEST_LENGTH);
icculus@53
   215
    SHA1Final(digest, &sha1);
icculus@53
   216
}
icculus@53
   217