base64.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 23 Jun 2017 17:28:03 -0400
changeset 58 1390348facc7
parent 0 d7ee4e2ed49d
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
/*
icculus@0
     2
cdecoder.c - c source to a base64 decoding algorithm implementation
icculus@0
     3
icculus@0
     4
This is part of the libb64 project, and has been placed in the public domain.
icculus@0
     5
For details, see http://sourceforge.net/projects/libb64
icculus@0
     6
*/
icculus@0
     7
icculus@0
     8
#include "base64.h"
icculus@0
     9
icculus@0
    10
int base64_decode_value(char value_in)
icculus@0
    11
{
icculus@0
    12
	static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
icculus@0
    13
	static const char decoding_size = sizeof(decoding);
icculus@0
    14
	value_in -= 43;
icculus@0
    15
	if (value_in < 0 || value_in > decoding_size) return -1;
icculus@0
    16
	return decoding[(int)value_in];
icculus@0
    17
}
icculus@0
    18
icculus@0
    19
void base64_init_decodestate(base64_decodestate* state_in)
icculus@0
    20
{
icculus@0
    21
	state_in->step = step_a;
icculus@0
    22
	state_in->plainchar = 0;
icculus@0
    23
}
icculus@0
    24
icculus@0
    25
int base64_decode_block(const char* code_in, const int length_in, uint8_t* plaintext_out, base64_decodestate* state_in)
icculus@0
    26
{
icculus@0
    27
	const char* codechar = code_in;
icculus@0
    28
	uint8_t* plainchar = plaintext_out;
icculus@0
    29
	char fragment;
icculus@0
    30
	
icculus@0
    31
	*plainchar = state_in->plainchar;
icculus@0
    32
	
icculus@0
    33
	switch (state_in->step)
icculus@0
    34
	{
icculus@0
    35
		while (1)
icculus@0
    36
		{
icculus@0
    37
	case step_a:
icculus@0
    38
			do {
icculus@0
    39
				if (codechar == code_in+length_in)
icculus@0
    40
				{
icculus@0
    41
					state_in->step = step_a;
icculus@0
    42
					state_in->plainchar = *plainchar;
icculus@0
    43
					return plainchar - plaintext_out;
icculus@0
    44
				}
icculus@0
    45
				fragment = (char)base64_decode_value(*codechar++);
icculus@0
    46
			} while (fragment < 0);
icculus@0
    47
			*plainchar    = (fragment & 0x03f) << 2;
icculus@0
    48
	case step_b:
icculus@0
    49
			do {
icculus@0
    50
				if (codechar == code_in+length_in)
icculus@0
    51
				{
icculus@0
    52
					state_in->step = step_b;
icculus@0
    53
					state_in->plainchar = *plainchar;
icculus@0
    54
					return plainchar - plaintext_out;
icculus@0
    55
				}
icculus@0
    56
				fragment = (char)base64_decode_value(*codechar++);
icculus@0
    57
			} while (fragment < 0);
icculus@0
    58
			*plainchar++ |= (fragment & 0x030) >> 4;
icculus@0
    59
			*plainchar    = (fragment & 0x00f) << 4;
icculus@0
    60
	case step_c:
icculus@0
    61
			do {
icculus@0
    62
				if (codechar == code_in+length_in)
icculus@0
    63
				{
icculus@0
    64
					state_in->step = step_c;
icculus@0
    65
					state_in->plainchar = *plainchar;
icculus@0
    66
					return plainchar - plaintext_out;
icculus@0
    67
				}
icculus@0
    68
				fragment = (char)base64_decode_value(*codechar++);
icculus@0
    69
			} while (fragment < 0);
icculus@0
    70
			*plainchar++ |= (fragment & 0x03c) >> 2;
icculus@0
    71
			*plainchar    = (fragment & 0x003) << 6;
icculus@0
    72
	case step_d:
icculus@0
    73
			do {
icculus@0
    74
				if (codechar == code_in+length_in)
icculus@0
    75
				{
icculus@0
    76
					state_in->step = step_d;
icculus@0
    77
					state_in->plainchar = *plainchar;
icculus@0
    78
					return plainchar - plaintext_out;
icculus@0
    79
				}
icculus@0
    80
				fragment = (char)base64_decode_value(*codechar++);
icculus@0
    81
			} while (fragment < 0);
icculus@0
    82
			*plainchar++   |= (fragment & 0x03f);
icculus@0
    83
		}
icculus@0
    84
	}
icculus@0
    85
	/* control should not reach here */
icculus@0
    86
	return plainchar - plaintext_out;
icculus@0
    87
}
icculus@0
    88
icculus@0
    89
/*
icculus@0
    90
cencoder.c - c source to a base64 encoding algorithm implementation
icculus@0
    91
icculus@0
    92
This is part of the libb64 project, and has been placed in the public domain.
icculus@0
    93
For details, see http://sourceforge.net/projects/libb64
icculus@0
    94
*/
icculus@0
    95
icculus@0
    96
const int CHARS_PER_LINE = 72;
icculus@0
    97
icculus@0
    98
void base64_init_encodestate(base64_encodestate* state_in)
icculus@0
    99
{
icculus@0
   100
	state_in->step = step_A;
icculus@0
   101
	state_in->result = 0;
icculus@0
   102
	state_in->stepcount = 0;
icculus@0
   103
}
icculus@0
   104
icculus@0
   105
char base64_encode_value(char value_in)
icculus@0
   106
{
icculus@0
   107
	static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
icculus@0
   108
	if (value_in > 63) return '=';
icculus@0
   109
	return encoding[(int)value_in];
icculus@0
   110
}
icculus@0
   111
icculus@0
   112
int base64_encode_block(const uint8_t* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
icculus@0
   113
{
icculus@0
   114
	const uint8_t* plainchar = plaintext_in;
icculus@0
   115
	const uint8_t* const plaintextend = plaintext_in + length_in;
icculus@0
   116
	char* codechar = code_out;
icculus@0
   117
	char result;
icculus@0
   118
	uint8_t fragment;
icculus@0
   119
	
icculus@0
   120
	result = state_in->result;
icculus@0
   121
	
icculus@0
   122
	switch (state_in->step)
icculus@0
   123
	{
icculus@0
   124
		while (1)
icculus@0
   125
		{
icculus@0
   126
	case step_A:
icculus@0
   127
			if (plainchar == plaintextend)
icculus@0
   128
			{
icculus@0
   129
				state_in->result = result;
icculus@0
   130
				state_in->step = step_A;
icculus@0
   131
				return codechar - code_out;
icculus@0
   132
			}
icculus@0
   133
			fragment = *plainchar++;
icculus@0
   134
			result = (fragment & 0x0fc) >> 2;
icculus@0
   135
			*codechar++ = base64_encode_value(result);
icculus@0
   136
			result = (fragment & 0x003) << 4;
icculus@0
   137
	case step_B:
icculus@0
   138
			if (plainchar == plaintextend)
icculus@0
   139
			{
icculus@0
   140
				state_in->result = result;
icculus@0
   141
				state_in->step = step_B;
icculus@0
   142
				return codechar - code_out;
icculus@0
   143
			}
icculus@0
   144
			fragment = *plainchar++;
icculus@0
   145
			result |= (fragment & 0x0f0) >> 4;
icculus@0
   146
			*codechar++ = base64_encode_value(result);
icculus@0
   147
			result = (fragment & 0x00f) << 2;
icculus@0
   148
	case step_C:
icculus@0
   149
			if (plainchar == plaintextend)
icculus@0
   150
			{
icculus@0
   151
				state_in->result = result;
icculus@0
   152
				state_in->step = step_C;
icculus@0
   153
				return codechar - code_out;
icculus@0
   154
			}
icculus@0
   155
			fragment = *plainchar++;
icculus@0
   156
			result |= (fragment & 0x0c0) >> 6;
icculus@0
   157
			*codechar++ = base64_encode_value(result);
icculus@0
   158
			result  = (fragment & 0x03f) >> 0;
icculus@0
   159
			*codechar++ = base64_encode_value(result);
icculus@0
   160
			
icculus@0
   161
			++(state_in->stepcount);
icculus@0
   162
			if (state_in->stepcount == CHARS_PER_LINE/4)
icculus@0
   163
			{
icculus@0
   164
				*codechar++ = '\n';
icculus@0
   165
				state_in->stepcount = 0;
icculus@0
   166
			}
icculus@0
   167
		}
icculus@0
   168
	}
icculus@0
   169
	/* control should not reach here */
icculus@0
   170
	return codechar - code_out;
icculus@0
   171
}
icculus@0
   172
icculus@0
   173
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
icculus@0
   174
{
icculus@0
   175
	char* codechar = code_out;
icculus@0
   176
	
icculus@0
   177
	switch (state_in->step)
icculus@0
   178
	{
icculus@0
   179
	case step_B:
icculus@0
   180
		*codechar++ = base64_encode_value(state_in->result);
icculus@0
   181
		*codechar++ = '=';
icculus@0
   182
		*codechar++ = '=';
icculus@0
   183
		break;
icculus@0
   184
	case step_C:
icculus@0
   185
		*codechar++ = base64_encode_value(state_in->result);
icculus@0
   186
		*codechar++ = '=';
icculus@0
   187
		break;
icculus@0
   188
	case step_A:
icculus@0
   189
		break;
icculus@0
   190
	}
icculus@0
   191
	*codechar++ = '\n';
icculus@0
   192
	
icculus@0
   193
	return codechar - code_out;
icculus@0
   194
}
icculus@0
   195
icculus@0
   196
// end of base64.c ...
icculus@0
   197