diff options
-rw-r--r-- | runtime/libgcry.c | 47 | ||||
-rw-r--r-- | runtime/libgcry.h | 40 | ||||
-rw-r--r-- | runtime/lmcry_gcry.c | 38 | ||||
-rw-r--r-- | runtime/rsyslog.h | 2 | ||||
-rw-r--r-- | tools/rscryutil.c | 67 | ||||
-rw-r--r-- | tools/rscryutil.rst | 43 |
6 files changed, 188 insertions, 49 deletions
diff --git a/runtime/libgcry.c b/runtime/libgcry.c index 5fd55360..ef94e8ac 100644 --- a/runtime/libgcry.c +++ b/runtime/libgcry.c @@ -49,8 +49,6 @@ #include "rsyslog.h" #include "libgcry.h" -#define GCRY_CIPHER GCRY_CIPHER_3DES // TODO: make configurable - static rsRetVal eiWriteRec(gcryfile gf, char *recHdr, size_t lenRecHdr, char *buf, size_t lenBuf) @@ -206,6 +204,8 @@ gcryCtxNew(void) { gcryctx ctx; ctx = calloc(1, sizeof(struct gcryctx_s)); + ctx->algo = GCRY_CIPHER_AES128; + ctx->mode = GCRY_CIPHER_MODE_CBC; return ctx; } @@ -270,9 +270,10 @@ done: return; int rsgcrySetKey(gcryctx ctx, unsigned char *key, uint16_t keyLen) { - uint16_t reqKeyLen = gcry_cipher_get_algo_keylen(GCRY_CIPHER); + uint16_t reqKeyLen; int r; + reqKeyLen = gcry_cipher_get_algo_keylen(ctx->algo); if(keyLen != reqKeyLen) { r = reqKeyLen; goto done; @@ -284,6 +285,36 @@ rsgcrySetKey(gcryctx ctx, unsigned char *key, uint16_t keyLen) done: return r; } +rsRetVal +rsgcrySetMode(gcryctx ctx, uchar *modename) +{ + int mode; + DEFiRet; + + mode = rsgcryModename2Mode((char *)modename); + if(mode == GCRY_CIPHER_MODE_NONE) { + ABORT_FINALIZE(RS_RET_CRY_INVLD_MODE); + } + ctx->mode = mode; +finalize_it: + RETiRet; +} + +rsRetVal +rsgcrySetAlgo(gcryctx ctx, uchar *algoname) +{ + int algo; + DEFiRet; + + algo = rsgcryAlgoname2Algo((char *)algoname); + if(algo == GCRY_CIPHER_NONE) { + ABORT_FINALIZE(RS_RET_CRY_INVLD_ALGO); + } + ctx->algo = algo; +finalize_it: + RETiRet; +} + /* As of some Linux and security expert I spoke to, /dev/urandom * provides very strong random numbers, even if it runs out of * entropy. As far as he knew, this is save for all applications @@ -310,7 +341,7 @@ seedIV(gcryfile gf, uchar **iv) } rsRetVal -rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, int gcry_mode, uchar *fname) +rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname) { gcry_error_t gcryError; gcryfile gf = NULL; @@ -319,13 +350,9 @@ rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, int gcry_mode, uchar *fname) CHKiRet(gcryfileConstruct(ctx, &gf, fname)); - gf->blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER); + gf->blkLength = gcry_cipher_get_algo_blklen(ctx->algo); - gcryError = gcry_cipher_open( - &gf->chd, // gcry_cipher_hd_t * - GCRY_CIPHER, // int - gcry_mode, // int - 0); // unsigned int + gcryError = gcry_cipher_open(&gf->chd, ctx->algo, ctx->mode, 0); if (gcryError) { dbgprintf("gcry_cipher_open failed: %s/%s\n", gcry_strsource(gcryError), diff --git a/runtime/libgcry.h b/runtime/libgcry.h index 857d2352..d699124d 100644 --- a/runtime/libgcry.h +++ b/runtime/libgcry.h @@ -26,6 +26,8 @@ struct gcryctx_s { uchar *key; size_t keyLen; + int algo; + int mode; }; typedef struct gcryctx_s *gcryctx; typedef struct gcryfile_s *gcryfile; @@ -42,10 +44,12 @@ struct gcryfile_s { int rsgcryInit(void); void rsgcryExit(void); int rsgcrySetKey(gcryctx ctx, unsigned char *key, uint16_t keyLen); +rsRetVal rsgcrySetMode(gcryctx ctx, uchar *algoname); +rsRetVal rsgcrySetAlgo(gcryctx ctx, uchar *modename); gcryctx gcryCtxNew(void); void rsgcryCtxDel(gcryctx ctx); int gcryfileDestruct(gcryfile gf, off64_t offsLogfile); -rsRetVal rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, int gcry_mode, uchar *fname); +rsRetVal rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname); int rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len); /* error states */ @@ -57,4 +61,38 @@ int rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len); #define RSGCRY_FILETYPE_NAME "rsyslog-enrcyption-info" #define ENCINFO_SUFFIX ".encinfo" +static inline int +rsgcryAlgoname2Algo(char *algoname) { + if(!strcmp((char*)algoname, "3DES")) return GCRY_CIPHER_3DES; + if(!strcmp((char*)algoname, "CAST5")) return GCRY_CIPHER_CAST5; + if(!strcmp((char*)algoname, "BLOWFISH")) return GCRY_CIPHER_BLOWFISH; + if(!strcmp((char*)algoname, "AES128")) return GCRY_CIPHER_AES128; + if(!strcmp((char*)algoname, "AES192")) return GCRY_CIPHER_AES192; + if(!strcmp((char*)algoname, "AES256")) return GCRY_CIPHER_AES256; + if(!strcmp((char*)algoname, "TWOFISH")) return GCRY_CIPHER_TWOFISH; + if(!strcmp((char*)algoname, "TWOFISH128")) return GCRY_CIPHER_TWOFISH128; + if(!strcmp((char*)algoname, "ARCFOUR")) return GCRY_CIPHER_ARCFOUR; + if(!strcmp((char*)algoname, "DES")) return GCRY_CIPHER_DES; + if(!strcmp((char*)algoname, "SERPENT128")) return GCRY_CIPHER_SERPENT128; + if(!strcmp((char*)algoname, "SERPENT192")) return GCRY_CIPHER_SERPENT192; + if(!strcmp((char*)algoname, "SERPENT256")) return GCRY_CIPHER_SERPENT256; + if(!strcmp((char*)algoname, "RFC2268_40")) return GCRY_CIPHER_RFC2268_40; + if(!strcmp((char*)algoname, "SEED")) return GCRY_CIPHER_SEED; + if(!strcmp((char*)algoname, "CAMELLIA128")) return GCRY_CIPHER_CAMELLIA128; + if(!strcmp((char*)algoname, "CAMELLIA192")) return GCRY_CIPHER_CAMELLIA192; + if(!strcmp((char*)algoname, "CAMELLIA256")) return GCRY_CIPHER_CAMELLIA256; + return GCRY_CIPHER_NONE; +} + +static inline int +rsgcryModename2Mode(char *modename) { + if(!strcmp((char*)modename, "ECB")) return GCRY_CIPHER_MODE_ECB; + if(!strcmp((char*)modename, "CFB")) return GCRY_CIPHER_MODE_CFB; + if(!strcmp((char*)modename, "CBC")) return GCRY_CIPHER_MODE_CBC; + if(!strcmp((char*)modename, "STREAM")) return GCRY_CIPHER_MODE_STREAM; + if(!strcmp((char*)modename, "OFB")) return GCRY_CIPHER_MODE_OFB; + if(!strcmp((char*)modename, "CTR")) return GCRY_CIPHER_MODE_CTR; + if(!strcmp((char*)modename, "AESWRAP")) return GCRY_CIPHER_MODE_AESWRAP; + return GCRY_CIPHER_MODE_NONE; +} #endif /* #ifndef INCLUDED_LIBGCRY_H */ diff --git a/runtime/lmcry_gcry.c b/runtime/lmcry_gcry.c index 881d047d..cc65051f 100644 --- a/runtime/lmcry_gcry.c +++ b/runtime/lmcry_gcry.c @@ -89,8 +89,9 @@ SetCnfParam(void *pT, struct nvlst *lst) { lmcry_gcry_t *pThis = (lmcry_gcry_t*) pT; int i, r; - uchar *cstr; uchar *key = NULL; + uchar *algo = NULL; + uchar *mode = NULL; struct cnfparamvals *pvals; DEFiRet; @@ -105,23 +106,30 @@ SetCnfParam(void *pT, struct nvlst *lst) continue; if(!strcmp(pblk.descr[i].name, "cry.key")) { key = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); -#if 0 - } else if(!strcmp(pblk.descr[i].name, "sig.timestampservice")) { - cstr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); - gcrySetTimestamper(pThis->ctx, (char*) cstr); - free(cstr); - } else if(!strcmp(pblk.descr[i].name, "sig.block.sizelimit")) { - gcrySetBlockSizeLimit(pThis->ctx, pvals[i].val.d.n); - } else if(!strcmp(pblk.descr[i].name, "sig.keeprecordhashes")) { - gcrySetKeepRecordHashes(pThis->ctx, pvals[i].val.d.n); - } else if(!strcmp(pblk.descr[i].name, "sig.keeptreehashes")) { - gcrySetKeepTreeHashes(pThis->ctx, pvals[i].val.d.n); + } else if(!strcmp(pblk.descr[i].name, "cry.mode")) { + mode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblk.descr[i].name, "cry.algo")) { + algo = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else { DBGPRINTF("lmcry_gcry: program error, non-handled " "param '%s'\n", pblk.descr[i].name); -#endif } } + if(algo != NULL) { + iRet = rsgcrySetAlgo(pThis->ctx, algo); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "cry.algo '%s' is not know/supported", algo); + FINALIZE; + } + } + if(mode != NULL) { + iRet = rsgcrySetMode(pThis->ctx, mode); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "cry.mode '%s' is not know/supported", mode); + FINALIZE; + } + } + /* note: key must be set AFTER algo/mode is set (as it depends on them) */ if(key != NULL) { errmsg.LogError(0, RS_RET_ERR, "Note: specifying an actual key directly from the " "config file is highly insecure - DO NOT USE FOR PRODUCTION"); @@ -138,6 +146,8 @@ SetCnfParam(void *pT, struct nvlst *lst) memset(key, 0, strlen((char*)key)); free(key); } + free(algo); + free(mode); finalize_it: RETiRet; } @@ -151,7 +161,7 @@ OnFileOpen(void *pT, uchar *fn, void *pGF) DEFiRet; dbgprintf("DDDD: cry: onFileOpen: %s\n", fn); - CHKiRet(rsgcryInitCrypt(pThis->ctx, pgf, GCRY_CIPHER_MODE_CBC, fn)); + CHKiRet(rsgcryInitCrypt(pThis->ctx, pgf, fn)); finalize_it: /* TODO: enable this error message (need to cleanup loop first ;)) errmsg.LogError(0, iRet, "Encryption Provider" diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index ab57eace..4cdd1c1e 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -408,6 +408,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_EI_NO_EXISTS = -2323,/**< .encinfo file does not exist (status, not necessarily error!)*/ RS_RET_EI_WR_ERR = -2324,/**< error writing an .encinfo file */ RS_RET_EI_INVLD_FILE = -2325,/**< header indicates the file is no .encinfo file */ + RS_RET_CRY_INVLD_ALGO = -2326,/**< user specified invalid (unkonwn) crypto algorithm */ + RS_RET_CRY_INVLD_MODE = -2327,/**< user specified invalid (unkonwn) crypto mode */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tools/rscryutil.c b/tools/rscryutil.c index e57eb625..e1e900a7 100644 --- a/tools/rscryutil.c +++ b/tools/rscryutil.c @@ -40,6 +40,9 @@ static int verbose = 0; static gcry_cipher_hd_t gcry_chd; static size_t blkLength; +static char *cry_key = NULL; +static int cry_algo = GCRY_CIPHER_AES128; +static int cry_mode = GCRY_CIPHER_MODE_CBC; /* rectype/value must be EIF_MAX_*_LEN+1 long! * returns 0 on success or something else on error/EOF @@ -151,14 +154,13 @@ done: return r; } static int -initCrypt(FILE *eifp, int gcry_mode, char *key) +initCrypt(FILE *eifp) { - #define GCRY_CIPHER GCRY_CIPHER_3DES // TODO: make configurable int r = 0; - gcry_error_t gcryError; + gcry_error_t gcryError; char iv[4096]; - blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER); + blkLength = gcry_cipher_get_algo_blklen(cry_algo); if(blkLength > sizeof(iv)) { fprintf(stderr, "internal error[%s:%d]: block length %d too large for " "iv buffer\n", __FILE__, __LINE__, blkLength); @@ -166,15 +168,15 @@ initCrypt(FILE *eifp, int gcry_mode, char *key) } if((r = eiGetIV(eifp, iv, blkLength)) != 0) goto done; - size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER); - if(strlen(key) != keyLength) { + size_t keyLength = gcry_cipher_get_algo_keylen(cry_algo); + if(strlen(cry_key) != keyLength) { fprintf(stderr, "invalid key length; key is %u characters, but " - "exactly %u characters are required\n", strlen(key), + "exactly %u characters are required\n", strlen(cry_key), keyLength); r = 1; goto done; } - gcryError = gcry_cipher_open(&gcry_chd, GCRY_CIPHER, gcry_mode, 0); + gcryError = gcry_cipher_open(&gcry_chd, cry_algo, cry_mode, 0); if (gcryError) { printf("gcry_cipher_open failed: %s/%s\n", gcry_strsource(gcryError), @@ -182,7 +184,7 @@ initCrypt(FILE *eifp, int gcry_mode, char *key) r = 1; goto done; } - gcryError = gcry_cipher_setkey(gcry_chd, key, keyLength); + gcryError = gcry_cipher_setkey(gcry_chd, cry_key, keyLength); if (gcryError) { printf("gcry_cipher_setkey failed: %s/%s\n", gcry_strsource(gcryError), @@ -225,10 +227,9 @@ done: return; static void decryptBlock(FILE *fpin, FILE *fpout, off64_t blkEnd, off64_t *pCurrOffs) { - gcry_error_t gcryError; + gcry_error_t gcryError; size_t nRead, nWritten; size_t toRead; - size_t nPad; size_t leftTillBlkEnd; char buf[64*1024]; @@ -240,7 +241,6 @@ decryptBlock(FILE *fpin, FILE *fpout, off64_t blkEnd, off64_t *pCurrOffs) if(nRead == 0) break; leftTillBlkEnd -= nRead, *pCurrOffs += nRead; - nPad = (blkLength - nRead % blkLength) % blkLength; gcryError = gcry_cipher_decrypt( gcry_chd, // gcry_cipher_hd_t buf, // void * @@ -248,7 +248,7 @@ decryptBlock(FILE *fpin, FILE *fpout, off64_t blkEnd, off64_t *pCurrOffs) NULL, // const void * 0); // size_t if (gcryError) { - fprintf(stderr, "gcry_cipher_encrypt failed: %s/%s\n", + fprintf(stderr, "gcry_cipher_decrypt failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); return; @@ -264,7 +264,7 @@ decryptBlock(FILE *fpin, FILE *fpout, off64_t blkEnd, off64_t *pCurrOffs) static int -doDecrypt(FILE *logfp, FILE *eifp, FILE *outfp, char *key) +doDecrypt(FILE *logfp, FILE *eifp, FILE *outfp) { off64_t blkEnd; off64_t currOffs = 0; @@ -272,7 +272,7 @@ doDecrypt(FILE *logfp, FILE *eifp, FILE *outfp, char *key) while(1) { /* process block */ - if(initCrypt(eifp, GCRY_CIPHER_MODE_CBC, key) != 0) + if(initCrypt(eifp) != 0) goto done; if((r = eiGetEND(eifp, &blkEnd)) != 0) goto done; decryptBlock(logfp, outfp, blkEnd, &currOffs); @@ -283,7 +283,7 @@ done: return r; } static void -decrypt(char *name, char *key) +decrypt(char *name) { FILE *logfp = NULL, *eifp = NULL; int r = 0; @@ -307,7 +307,7 @@ decrypt(char *name, char *key) goto err; } - doDecrypt(logfp, eifp, stdout, key); + doDecrypt(logfp, eifp, stdout); fclose(logfp); logfp = NULL; fclose(eifp); eifp = NULL; @@ -326,6 +326,8 @@ static struct option long_options[] = {"version", no_argument, NULL, 'V'}, {"decrypt", no_argument, NULL, 'd'}, {"key", required_argument, NULL, 'k'}, + {"algo", required_argument, NULL, 'a'}, + {"mode", required_argument, NULL, 'm'}, {NULL, 0, NULL, 0} }; @@ -334,10 +336,10 @@ main(int argc, char *argv[]) { int i; int opt; - char *key = ""; + int temp; while(1) { - opt = getopt_long(argc, argv, "dk:vV", long_options, NULL); + opt = getopt_long(argc, argv, "a:dk:m:vV", long_options, NULL); if(opt == -1) break; switch(opt) { @@ -348,7 +350,25 @@ main(int argc, char *argv[]) fprintf(stderr, "WARNING: specifying the actual key " "via the command line is highly insecure\n" "Do NOT use this for PRODUCTION use.\n"); - key = optarg; + cry_key = optarg; + break; + case 'a': + temp = rsgcryAlgoname2Algo(optarg); + if(temp == GCRY_CIPHER_NONE) { + fprintf(stderr, "ERROR: algorithm \"%s\" is not " + "kown/supported\n", optarg); + exit(1); + } + cry_algo = temp; + break; + case 'm': + temp = rsgcryModename2Mode(optarg); + if(temp == GCRY_CIPHER_MODE_NONE) { + fprintf(stderr, "ERROR: cipher mode \"%s\" is not " + "kown/supported\n", optarg); + exit(1); + } + cry_mode = temp; break; case 'v': verbose = 1; @@ -365,13 +385,12 @@ main(int argc, char *argv[]) } if(optind == argc) - decrypt("-", key); + decrypt("-"); else { for(i = optind ; i < argc ; ++i) - decrypt(argv[i], key); /* currently only mode ;) */ + decrypt(argv[i]); /* currently only mode ;) */ } - memset(key, 0, strlen(key)); /* zero-out key store */ + memset(cry_key, 0, strlen(cry_key)); /* zero-out key store */ return 0; } - //char *aesSymKey = "123456789012345678901234"; // TODO: TEST ONLY diff --git a/tools/rscryutil.rst b/tools/rscryutil.rst index 7e3ab5b4..3cc54f57 100644 --- a/tools/rscryutil.rst +++ b/tools/rscryutil.rst @@ -40,6 +40,13 @@ OPTIONS is highly insecure. However, it can be useful for intial testing steps. This option may be removed in the future. +-a, --algo <algo> + Sets the encryption algorightm (cipher) to be used. See below + for supported algorithms. The default is "AES128". + +-m, --mode <mode> + Sets the ciphermode to be used. See below for supported modes. + The default is "CBC". OPERATION MODES =============== @@ -62,6 +69,42 @@ The command returns an exit code of 0 if everything went fine, and some other code in case of failures. +SUPPORTED ALGORITHMS +==================== + +We basically support what libgcrypt supports. This is: + 3DES + CAST5 + BLOWFISH + AES128 + AES192 + AES256 + TWOFISH + TWOFISH128 + ARCFOUR + DES + SERPENT128 + SERPENT192 + SERPENT256 + RFC2268_40 + SEED + CAMELLIA128 + CAMELLIA192 + CAMELLIA256 + + +SUPPORTED CIPHER MODES +====================== + +We basically support what libgcrypt supports. This is: + ECB + CFB + CBC + STREAM + OFB + CTR + AESWRAP + EXAMPLES ======== |