lua/lopcodes.h
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
** $Id: lopcodes.h,v 1.142.1.1 2013/04/12 18:48:47 roberto Exp $
icculus@0
     3
** Opcodes for Lua virtual machine
icculus@0
     4
** See Copyright Notice in lua.h
icculus@0
     5
*/
icculus@0
     6
icculus@0
     7
#ifndef lopcodes_h
icculus@0
     8
#define lopcodes_h
icculus@0
     9
icculus@0
    10
#include "llimits.h"
icculus@0
    11
icculus@0
    12
icculus@0
    13
/*===========================================================================
icculus@0
    14
  We assume that instructions are unsigned numbers.
icculus@0
    15
  All instructions have an opcode in the first 6 bits.
icculus@0
    16
  Instructions can have the following fields:
icculus@0
    17
	`A' : 8 bits
icculus@0
    18
	`B' : 9 bits
icculus@0
    19
	`C' : 9 bits
icculus@0
    20
	'Ax' : 26 bits ('A', 'B', and 'C' together)
icculus@0
    21
	`Bx' : 18 bits (`B' and `C' together)
icculus@0
    22
	`sBx' : signed Bx
icculus@0
    23
icculus@0
    24
  A signed argument is represented in excess K; that is, the number
icculus@0
    25
  value is the unsigned value minus K. K is exactly the maximum value
icculus@0
    26
  for that argument (so that -max is represented by 0, and +max is
icculus@0
    27
  represented by 2*max), which is half the maximum for the corresponding
icculus@0
    28
  unsigned argument.
icculus@0
    29
===========================================================================*/
icculus@0
    30
icculus@0
    31
icculus@0
    32
enum OpMode {iABC, iABx, iAsBx, iAx};  /* basic instruction format */
icculus@0
    33
icculus@0
    34
icculus@0
    35
/*
icculus@0
    36
** size and position of opcode arguments.
icculus@0
    37
*/
icculus@0
    38
#define SIZE_C		9
icculus@0
    39
#define SIZE_B		9
icculus@0
    40
#define SIZE_Bx		(SIZE_C + SIZE_B)
icculus@0
    41
#define SIZE_A		8
icculus@0
    42
#define SIZE_Ax		(SIZE_C + SIZE_B + SIZE_A)
icculus@0
    43
icculus@0
    44
#define SIZE_OP		6
icculus@0
    45
icculus@0
    46
#define POS_OP		0
icculus@0
    47
#define POS_A		(POS_OP + SIZE_OP)
icculus@0
    48
#define POS_C		(POS_A + SIZE_A)
icculus@0
    49
#define POS_B		(POS_C + SIZE_C)
icculus@0
    50
#define POS_Bx		POS_C
icculus@0
    51
#define POS_Ax		POS_A
icculus@0
    52
icculus@0
    53
icculus@0
    54
/*
icculus@0
    55
** limits for opcode arguments.
icculus@0
    56
** we use (signed) int to manipulate most arguments,
icculus@0
    57
** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
icculus@0
    58
*/
icculus@0
    59
#if SIZE_Bx < LUAI_BITSINT-1
icculus@0
    60
#define MAXARG_Bx        ((1<<SIZE_Bx)-1)
icculus@0
    61
#define MAXARG_sBx        (MAXARG_Bx>>1)         /* `sBx' is signed */
icculus@0
    62
#else
icculus@0
    63
#define MAXARG_Bx        MAX_INT
icculus@0
    64
#define MAXARG_sBx        MAX_INT
icculus@0
    65
#endif
icculus@0
    66
icculus@0
    67
#if SIZE_Ax < LUAI_BITSINT-1
icculus@0
    68
#define MAXARG_Ax	((1<<SIZE_Ax)-1)
icculus@0
    69
#else
icculus@0
    70
#define MAXARG_Ax	MAX_INT
icculus@0
    71
#endif
icculus@0
    72
icculus@0
    73
icculus@0
    74
#define MAXARG_A        ((1<<SIZE_A)-1)
icculus@0
    75
#define MAXARG_B        ((1<<SIZE_B)-1)
icculus@0
    76
#define MAXARG_C        ((1<<SIZE_C)-1)
icculus@0
    77
icculus@0
    78
icculus@0
    79
/* creates a mask with `n' 1 bits at position `p' */
icculus@0
    80
#define MASK1(n,p)	((~((~(Instruction)0)<<(n)))<<(p))
icculus@0
    81
icculus@0
    82
/* creates a mask with `n' 0 bits at position `p' */
icculus@0
    83
#define MASK0(n,p)	(~MASK1(n,p))
icculus@0
    84
icculus@0
    85
/*
icculus@0
    86
** the following macros help to manipulate instructions
icculus@0
    87
*/
icculus@0
    88
icculus@0
    89
#define GET_OPCODE(i)	(cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
icculus@0
    90
#define SET_OPCODE(i,o)	((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
icculus@0
    91
		((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
icculus@0
    92
icculus@0
    93
#define getarg(i,pos,size)	(cast(int, ((i)>>pos) & MASK1(size,0)))
icculus@0
    94
#define setarg(i,v,pos,size)	((i) = (((i)&MASK0(size,pos)) | \
icculus@0
    95
                ((cast(Instruction, v)<<pos)&MASK1(size,pos))))
icculus@0
    96
icculus@0
    97
#define GETARG_A(i)	getarg(i, POS_A, SIZE_A)
icculus@0
    98
#define SETARG_A(i,v)	setarg(i, v, POS_A, SIZE_A)
icculus@0
    99
icculus@0
   100
#define GETARG_B(i)	getarg(i, POS_B, SIZE_B)
icculus@0
   101
#define SETARG_B(i,v)	setarg(i, v, POS_B, SIZE_B)
icculus@0
   102
icculus@0
   103
#define GETARG_C(i)	getarg(i, POS_C, SIZE_C)
icculus@0
   104
#define SETARG_C(i,v)	setarg(i, v, POS_C, SIZE_C)
icculus@0
   105
icculus@0
   106
#define GETARG_Bx(i)	getarg(i, POS_Bx, SIZE_Bx)
icculus@0
   107
#define SETARG_Bx(i,v)	setarg(i, v, POS_Bx, SIZE_Bx)
icculus@0
   108
icculus@0
   109
#define GETARG_Ax(i)	getarg(i, POS_Ax, SIZE_Ax)
icculus@0
   110
#define SETARG_Ax(i,v)	setarg(i, v, POS_Ax, SIZE_Ax)
icculus@0
   111
icculus@0
   112
#define GETARG_sBx(i)	(GETARG_Bx(i)-MAXARG_sBx)
icculus@0
   113
#define SETARG_sBx(i,b)	SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
icculus@0
   114
icculus@0
   115
icculus@0
   116
#define CREATE_ABC(o,a,b,c)	((cast(Instruction, o)<<POS_OP) \
icculus@0
   117
			| (cast(Instruction, a)<<POS_A) \
icculus@0
   118
			| (cast(Instruction, b)<<POS_B) \
icculus@0
   119
			| (cast(Instruction, c)<<POS_C))
icculus@0
   120
icculus@0
   121
#define CREATE_ABx(o,a,bc)	((cast(Instruction, o)<<POS_OP) \
icculus@0
   122
			| (cast(Instruction, a)<<POS_A) \
icculus@0
   123
			| (cast(Instruction, bc)<<POS_Bx))
icculus@0
   124
icculus@0
   125
#define CREATE_Ax(o,a)		((cast(Instruction, o)<<POS_OP) \
icculus@0
   126
			| (cast(Instruction, a)<<POS_Ax))
icculus@0
   127
icculus@0
   128
icculus@0
   129
/*
icculus@0
   130
** Macros to operate RK indices
icculus@0
   131
*/
icculus@0
   132
icculus@0
   133
/* this bit 1 means constant (0 means register) */
icculus@0
   134
#define BITRK		(1 << (SIZE_B - 1))
icculus@0
   135
icculus@0
   136
/* test whether value is a constant */
icculus@0
   137
#define ISK(x)		((x) & BITRK)
icculus@0
   138
icculus@0
   139
/* gets the index of the constant */
icculus@0
   140
#define INDEXK(r)	((int)(r) & ~BITRK)
icculus@0
   141
icculus@0
   142
#define MAXINDEXRK	(BITRK - 1)
icculus@0
   143
icculus@0
   144
/* code a constant index as a RK value */
icculus@0
   145
#define RKASK(x)	((x) | BITRK)
icculus@0
   146
icculus@0
   147
icculus@0
   148
/*
icculus@0
   149
** invalid register that fits in 8 bits
icculus@0
   150
*/
icculus@0
   151
#define NO_REG		MAXARG_A
icculus@0
   152
icculus@0
   153
icculus@0
   154
/*
icculus@0
   155
** R(x) - register
icculus@0
   156
** Kst(x) - constant (in constant table)
icculus@0
   157
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
icculus@0
   158
*/
icculus@0
   159
icculus@0
   160
icculus@0
   161
/*
icculus@0
   162
** grep "ORDER OP" if you change these enums
icculus@0
   163
*/
icculus@0
   164
icculus@0
   165
typedef enum {
icculus@0
   166
/*----------------------------------------------------------------------
icculus@0
   167
name		args	description
icculus@0
   168
------------------------------------------------------------------------*/
icculus@0
   169
OP_MOVE,/*	A B	R(A) := R(B)					*/
icculus@0
   170
OP_LOADK,/*	A Bx	R(A) := Kst(Bx)					*/
icculus@0
   171
OP_LOADKX,/*	A 	R(A) := Kst(extra arg)				*/
icculus@0
   172
OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/
icculus@0
   173
OP_LOADNIL,/*	A B	R(A), R(A+1), ..., R(A+B) := nil		*/
icculus@0
   174
OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/
icculus@0
   175
icculus@0
   176
OP_GETTABUP,/*	A B C	R(A) := UpValue[B][RK(C)]			*/
icculus@0
   177
OP_GETTABLE,/*	A B C	R(A) := R(B)[RK(C)]				*/
icculus@0
   178
icculus@0
   179
OP_SETTABUP,/*	A B C	UpValue[A][RK(B)] := RK(C)			*/
icculus@0
   180
OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
icculus@0
   181
OP_SETTABLE,/*	A B C	R(A)[RK(B)] := RK(C)				*/
icculus@0
   182
icculus@0
   183
OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/
icculus@0
   184
icculus@0
   185
OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]		*/
icculus@0
   186
icculus@0
   187
OP_ADD,/*	A B C	R(A) := RK(B) + RK(C)				*/
icculus@0
   188
OP_SUB,/*	A B C	R(A) := RK(B) - RK(C)				*/
icculus@0
   189
OP_MUL,/*	A B C	R(A) := RK(B) * RK(C)				*/
icculus@0
   190
OP_DIV,/*	A B C	R(A) := RK(B) / RK(C)				*/
icculus@0
   191
OP_MOD,/*	A B C	R(A) := RK(B) % RK(C)				*/
icculus@0
   192
OP_POW,/*	A B C	R(A) := RK(B) ^ RK(C)				*/
icculus@0
   193
OP_UNM,/*	A B	R(A) := -R(B)					*/
icculus@0
   194
OP_NOT,/*	A B	R(A) := not R(B)				*/
icculus@0
   195
OP_LEN,/*	A B	R(A) := length of R(B)				*/
icculus@0
   196
icculus@0
   197
OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
icculus@0
   198
icculus@0
   199
OP_JMP,/*	A sBx	pc+=sBx; if (A) close all upvalues >= R(A) + 1	*/
icculus@0
   200
OP_EQ,/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++		*/
icculus@0
   201
OP_LT,/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++		*/
icculus@0
   202
OP_LE,/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++		*/
icculus@0
   203
icculus@0
   204
OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/
icculus@0
   205
OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/
icculus@0
   206
icculus@0
   207
OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
icculus@0
   208
OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
icculus@0
   209
OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
icculus@0
   210
icculus@0
   211
OP_FORLOOP,/*	A sBx	R(A)+=R(A+2);
icculus@0
   212
			if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
icculus@0
   213
OP_FORPREP,/*	A sBx	R(A)-=R(A+2); pc+=sBx				*/
icculus@0
   214
icculus@0
   215
OP_TFORCALL,/*	A C	R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));	*/
icculus@0
   216
OP_TFORLOOP,/*	A sBx	if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
icculus@0
   217
icculus@0
   218
OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/
icculus@0
   219
icculus@0
   220
OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx])			*/
icculus@0
   221
icculus@0
   222
OP_VARARG,/*	A B	R(A), R(A+1), ..., R(A+B-2) = vararg		*/
icculus@0
   223
icculus@0
   224
OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
icculus@0
   225
} OpCode;
icculus@0
   226
icculus@0
   227
icculus@0
   228
#define NUM_OPCODES	(cast(int, OP_EXTRAARG) + 1)
icculus@0
   229
icculus@0
   230
icculus@0
   231
icculus@0
   232
/*===========================================================================
icculus@0
   233
  Notes:
icculus@0
   234
  (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is
icculus@0
   235
  set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
icculus@0
   236
  OP_SETLIST) may use `top'.
icculus@0
   237
icculus@0
   238
  (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
icculus@0
   239
  set top (like in OP_CALL with C == 0).
icculus@0
   240
icculus@0
   241
  (*) In OP_RETURN, if (B == 0) then return up to `top'.
icculus@0
   242
icculus@0
   243
  (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next
icculus@0
   244
  'instruction' is EXTRAARG(real C).
icculus@0
   245
icculus@0
   246
  (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
icculus@0
   247
icculus@0
   248
  (*) For comparisons, A specifies what condition the test should accept
icculus@0
   249
  (true or false).
icculus@0
   250
icculus@0
   251
  (*) All `skips' (pc++) assume that next instruction is a jump.
icculus@0
   252
icculus@0
   253
===========================================================================*/
icculus@0
   254
icculus@0
   255
icculus@0
   256
/*
icculus@0
   257
** masks for instruction properties. The format is:
icculus@0
   258
** bits 0-1: op mode
icculus@0
   259
** bits 2-3: C arg mode
icculus@0
   260
** bits 4-5: B arg mode
icculus@0
   261
** bit 6: instruction set register A
icculus@0
   262
** bit 7: operator is a test (next instruction must be a jump)
icculus@0
   263
*/
icculus@0
   264
icculus@0
   265
enum OpArgMask {
icculus@0
   266
  OpArgN,  /* argument is not used */
icculus@0
   267
  OpArgU,  /* argument is used */
icculus@0
   268
  OpArgR,  /* argument is a register or a jump offset */
icculus@0
   269
  OpArgK   /* argument is a constant or register/constant */
icculus@0
   270
};
icculus@0
   271
icculus@0
   272
LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES];
icculus@0
   273
icculus@0
   274
#define getOpMode(m)	(cast(enum OpMode, luaP_opmodes[m] & 3))
icculus@0
   275
#define getBMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
icculus@0
   276
#define getCMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
icculus@0
   277
#define testAMode(m)	(luaP_opmodes[m] & (1 << 6))
icculus@0
   278
#define testTMode(m)	(luaP_opmodes[m] & (1 << 7))
icculus@0
   279
icculus@0
   280
icculus@0
   281
LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1];  /* opcode names */
icculus@0
   282
icculus@0
   283
icculus@0
   284
/* number of list items to accumulate before a SETLIST instruction */
icculus@0
   285
#define LFIELDS_PER_FLUSH	50
icculus@0
   286
icculus@0
   287
icculus@0
   288
#endif