Commit 1bc69443 authored by davxy's avatar davxy

CBC block mode of operation using a generic block cipher interface.

Additional utilities: memxor
parent 6910a921
......@@ -27,6 +27,8 @@ Unreleased
### Added
- CBC block cipher mode of operation
- AES block cipher
- DES block cipher
- Base64 encoder/decoder
......@@ -7,9 +7,11 @@ CFLAGS := -O0 -g
CPPFLAGS := -Iinclude
OBJS := src/cry_version.o \
src/cry_memxor.o \
src/cry_base64.o \
src/cry_des.o \
src/cry_aes.o
src/cry_aes.o \
src/cry_cbc.o
.PHONY: all clean
......
CRY
===
CRY(T_T)
========
A small crypto library
Block ciphers
-------------
- AES
- DES and TDES
### Block cipher mode of operation
- ECB
- CBC
Utilities
---------
- Base64 encoder/decoder
......@@ -30,6 +30,8 @@
#include "cry_base64.h"
#include "cry_des.h"
#include "cry_aes.h"
#include "cry_cbc.h"
#include "cry_ciph.h"
#endif /* _CRY_H_ */
/*
* Copyright (c) 2013, Davide Galassi. All rights reserved.
*
* This file is part of CRY software.
*
* CRY is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CRY; if not, see <http://www.gnu/licenses/>.
*/
/**
* @file cry_cbc.h
* @brief CBC block cipher mode of operation.
*/
#ifndef _CRY_CBC_H_
#define _CRY_CBC_H_
#include "cry_ciph.h"
/** CTR block size. */
#define CRY_CBC_BLOCK_SIZE 16
/** Convenience macro to initialize a CBC context. */
#define CRY_CBC_INIT(ctx, _crypto_ctx, _crypto_itf) do { \
memset((ctx), 0U, sizeof(struct cry_cbc_ctx)); \
(ctx)->ciph_ctx = (_crypto_ctx); \
(ctx)->ciph_itf = (_crypto_itf); \
} while(0)
/** CBC context structure. */
struct cry_cbc_ctx {
const struct cry_ciph_itf *ciph_itf; /** Block cipher interface. */
void *ciph_ctx; /** Block cipher context. */
unsigned char v[CRY_CBC_BLOCK_SIZE]; /* Counter. */
};
typedef struct cry_cbc_ctx cry_cbc_ctx;
#ifdef __cplusplus
extern "C"{
#endif
/**
* Set the cipher key.
*
* @param ctx CBC context.
* @param key Cipher key.
* @param size Cipher key size.
*/
void cry_cbc_key_set(struct cry_cbc_ctx *ctx, const unsigned char *key,
unsigned int size);
/**
* Set the initialization vector.
*
* @param ctx CBC context.
* @param iv Initialization vector.
* @param size Initialization vector size.
*/
void cry_cbc_iv_set(struct cry_cbc_ctx *ctx, const unsigned char *iv,
unsigned int size);
/**
* Encryption function.
*
* @param ctx CBC context.
* @param dst Destination buffer (ciphertext).
* @param src Source buffer (cleartext).
* @param size Size should be a multiple of CBC_BLOCK_SIZE
*/
void cry_cbc_encrypt(struct cry_cbc_ctx *ctx, unsigned char *dst,
const unsigned char *src, unsigned int size);
/**
* Decryption function.
*
* @param ctx CBC context.
* @param dst Destination buffer (cleartext).
* @param src Source buffer (ciphertext).
* @param size Size should be a multiple of CBC_BLOCK_SIZE.
*/
void cry_cbc_decrypt(struct cry_cbc_ctx *ctx, unsigned char *dst,
const unsigned char *src, unsigned int size);
#ifdef __cplusplus
}
#endif
#endif /* _CRY_CBC_H_ */
/*
* Copyright (c) 2013, Davide Galassi. All rights reserved.
*
* This file is part of CRY software.
*
* CRY is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CRY; if not, see <http://www.gnu/licenses/>.
*/
/**
* @file cry_ciph.h
* @brief Generic cipher interface
*/
#ifndef _CRY_CIPH_H_
#define _CRY_CIPH_H_
#ifdef __cplusplus
extern "C"{
#endif
/**
* Context initialization function pointer type.
*
* @param ctx Cipher context
*/
typedef void (* cry_ciph_init_f)(void *ctx);
/**
* Context cleanup function pointer type.
*
* @param ctx Cipher context
*/
typedef void (* cry_ciph_clean_f)(void *ctx);
/**
* Key set function pointer type.
*
* @param ctx Cipher context.
* @param key Cipher key.
* @param size Key size.
*/
typedef void (* cry_ciph_key_set_f)(void *ctx, const unsigned char *key,
unsigned int size);
/**
* Encrypt function pointer type.
*
* @param ctx Cipher context.
* @param dst Destination buffer.
* @param src Source buffer.
* @param size Size of source/destination buffers.
*/
typedef void (* cry_ciph_encrypt_f)(void *ctx, unsigned char *dst,
const unsigned char *src,
unsigned int size);
/**
* Decrypt function pointer type.
*
* @param ctx Cipher context.
* @param dst Destination buffer.
* @param src Source buffer.
* @param size Size of source/destination buffers.
*/
typedef void (* cry_ciph_decrypt_f)(void *ctx, unsigned char *dst,
const unsigned char *src,
unsigned int size);
#ifdef __cplusplus
}
#endif
/**
* Cipher algorithm generic interface.
*/
struct cry_ciph_itf {
cry_ciph_init_f init;
cry_ciph_clean_f clean;
cry_ciph_key_set_f key_set;
cry_ciph_encrypt_f encrypt;
cry_ciph_decrypt_f decrypt;
};
typedef struct cry_ciph_itf cry_ciph_itf;
#endif /* _CRY_CIPH_H_ */
/*
* Copyright (c) 2013, Davide Galassi. All rights reserved.
*
* This file is part of CRY software.
*
* CRY is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CRY; if not, see <http://www.gnu/licenses/>.
*/
#include "cry_cbc.h"
#include "cry_ciph.h"
#include "cry_memxor.h"
#include "cry_misc.h"
#include <string.h>
#include <stdlib.h>
void cry_cbc_key_set(struct cry_cbc_ctx *ctx, const unsigned char *key,
unsigned int size)
{
void *ciph = ctx->ciph_ctx;
cry_ciph_key_set_f key_set = ctx->ciph_itf->key_set;
key_set(ciph, key, size);
}
void cry_cbc_iv_set(struct cry_cbc_ctx *ctx, const unsigned char *iv,
unsigned int size)
{
size = CRY_MIN(CRY_CBC_BLOCK_SIZE, size);
memcpy(ctx->v, iv, size);
memset(ctx->v + size, 0, CRY_CBC_BLOCK_SIZE - size);
}
void cry_cbc_encrypt(struct cry_cbc_ctx *ctx, unsigned char *dst,
const unsigned char *src, unsigned int size)
{
void *ciph = ctx->ciph_ctx;
cry_ciph_encrypt_f encrypt = ctx->ciph_itf->encrypt;
size &= ~(CRY_CBC_BLOCK_SIZE - 1);
while (size != 0) {
cry_memxor(ctx->v, src, CRY_CBC_BLOCK_SIZE);
encrypt(ciph, dst, ctx->v, CRY_CBC_BLOCK_SIZE);
memcpy(ctx->v, dst, CRY_CBC_BLOCK_SIZE);
src += CRY_CBC_BLOCK_SIZE;
dst += CRY_CBC_BLOCK_SIZE;
size -= CRY_CBC_BLOCK_SIZE;
}
}
//#define CBC_BUFFER_LIMIT 512
#define CBC_BUFFER_LIMIT 16
void cry_cbc_decrypt(struct cry_cbc_ctx *ctx, unsigned char *dst,
const unsigned char *src, unsigned int size)
{
void *ciph = ctx->ciph_ctx;
cry_ciph_encrypt_f decrypt = ctx->ciph_itf->decrypt;
size &= ~(CRY_CBC_BLOCK_SIZE - 1);
if (src != dst) {
decrypt(ciph, dst, src, size);
cry_memxor(dst, ctx->v, CRY_CBC_BLOCK_SIZE);
cry_memxor(dst + CRY_CBC_BLOCK_SIZE, src, size - CRY_CBC_BLOCK_SIZE);
memcpy(ctx->v, src + size - CRY_CBC_BLOCK_SIZE, CRY_CBC_BLOCK_SIZE);
} else {
/*
* For in-place CBC, we decrypt into a temporary buffer of size
* at most CBC_BUFFER_LIMIT, and process that amount of data at
* a time.
*/
unsigned char initial_iv[CRY_CBC_BLOCK_SIZE];
unsigned char fallback[CRY_CBC_BLOCK_SIZE]; /* if malloc fails */
unsigned char *buffer;
unsigned int buffer_size = CRY_MIN(size, CBC_BUFFER_LIMIT);
buffer = malloc(buffer_size);
if (buffer == NULL) {
buffer = fallback;
buffer_size = CRY_CBC_BLOCK_SIZE;
}
for ( ; size > buffer_size;
size -= buffer_size, src += buffer_size, dst += buffer_size) {
decrypt(ciph, buffer, src, buffer_size);
memcpy(initial_iv, ctx->v, CRY_CBC_BLOCK_SIZE);
memcpy(ctx->v, src + buffer_size - CRY_CBC_BLOCK_SIZE,
CRY_CBC_BLOCK_SIZE);
cry_memxor3(dst + CRY_CBC_BLOCK_SIZE, buffer + CRY_CBC_BLOCK_SIZE,
src, buffer_size - CRY_CBC_BLOCK_SIZE);
cry_memxor3(dst, buffer, initial_iv, CRY_CBC_BLOCK_SIZE);
}
decrypt(ciph, buffer, src, size);
memcpy(initial_iv, ctx->v, CRY_CBC_BLOCK_SIZE);
/* Copies last block */
memcpy(ctx->v, src + size - CRY_CBC_BLOCK_SIZE, CRY_CBC_BLOCK_SIZE);
/* Writes all but first block, reads all but last block. */
cry_memxor3(dst + CRY_CBC_BLOCK_SIZE, buffer + CRY_CBC_BLOCK_SIZE,
src, size - CRY_CBC_BLOCK_SIZE);
/* Writes first block. */
cry_memxor3(dst, buffer, initial_iv, CRY_CBC_BLOCK_SIZE);
if (buffer != fallback)
free(buffer);
}
}
/*
* Copyright (c) 2013, Davide Galassi. All rights reserved.
*
* This file is part of CRY software.
*
* CRY is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CRY; if not, see <http://www.gnu/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
void cry_memxor3_worst(unsigned char *dst, const unsigned char *src1,
const unsigned char *src2, unsigned int size)
{
unsigned int i;
unsigned char *tmp;
tmp = malloc(size);
if (tmp != NULL) {
for (i = 0; i < size; i++)
tmp[i] = src1[i] ^ src2[i];
memcpy(dst, tmp, size);
free(tmp);
} else {
/*
* TODO: this could be a security issue FIXME
*/
}
}
/* We assume src1 <= src2
*
* CASE 1 : Start from the beginning
*
* 1.a) dst is less than or equal both.
* src1 : [----------]
* src2 : [----------]
* dst : [----------]
*
* 1.b) src1 and src2 are disjointed AND dst is less than or equal src2
* src1 : [----------]
* src2 : [----------]
* dst : [----------]
*
* CASE 2: Start from the end
*
* 2.a) dst is greater than or equal both
* src1 : [----------]
* src2 : [----------]
* dst : [----------]
*
* 2.b) src1 and src2 are disjointed AND dst+n is smaller than or equal src2
* src1 : [----------]
* src2 : [----------]
* dst : [----------]
*
* CASE 3: src1 and src2 are disjointed but dst contains the end of src1 and
* the start of src2.
* Start from k and finally rotate the result buffer at the end.
*
* src1 : [----------]
* src2 : [----------]
* dst : [---k------]
*
* CASE 4: worst case, use malloc for temporary allocation.
* Inplace implementation is still possible but is not implemented.
*/
void cry_memxor3(unsigned char *dst, const unsigned char *src1,
const unsigned char *src2, unsigned int n)
{
unsigned int i;
if (src2 < src1) {
const unsigned char *tmp = src1;
src1 = src2;
src2 = tmp;
}
if ((dst <= src1) || ((src1+n <= dst) && (dst <= src2))) {
/* Case 1 */
for (i = 0; i < n; i++)
dst[i] = src1[i] ^ src2[i];
} else if ((src2 <= dst) || ((src1 <= dst) && (dst+n <= src2))) {
/* Case 2 */
while(n != 0) {
n--;
dst[n] = src1[n] ^ src2[n];
}
}
#if 0 /* TODO: EXAMINATE better before production */
/* Case 3 */
else if (disjoint == TRUE) {
}
#endif
/* Case 4 */
else {
cry_memxor3_worst(dst, src1, src2, n);
}
}
void cry_memxor(unsigned char *dst, const unsigned char *src,
unsigned int n)
{
if (dst <= src) {
while (n--)
*dst++ ^= *src++;
} else {
while (n--)
dst[n] ^= src[n];
}
}
/*
* Copyright (c) 2013, Davide Galassi. All rights reserved.
*
* This file is part of CRY software.
*
* CRY is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CRY; if not, see <http://www.gnu/licenses/>.
*/
#ifndef _CRY_MEMXOR_H_
#define _CRY_MEMXOR_H_
#ifdef __cplusplus
extern "C"{
#endif
/**
* XOR two memory regions.
*
* The result is stored in the first operand.
* The memory segments may overlap and can work inplace.
*
* @param dst First source and destination.
* @param src Second source.
* @param size Number of bytes to XOR.
*/
void cry_memxor(unsigned char *dst, const unsigned char *src,
unsigned int size);
/**
* XOR two memory regions.
*
* The memory segments may overlap and can work inplace.
*
* @param dst Destination.
* @param src1 First source.
* @param src2 Second source.
* @param size Number of bytes to XOR.
*/
void cry_memxor3(unsigned char *dst, const unsigned char *src1,
const unsigned char *src2, unsigned int size);
#ifdef __cplusplus
}
#endif
#endif /* _CRY_MEMXOR_H_ */
/*
* Copyright (c) 2013, Davide Galassi. All rights reserved.
*
* This file is part of CRY software.
*
* CRY is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CRY; if not, see <http://www.gnu/licenses/>.
*/
/*
* A bounch of helper macros and functions meant for internal use.
*/
#ifndef _CRY_MISC_H_
#define _CRY_MISC_H_
/** Statically get array number of elements */
#define CRY_ARRAY_LEN(ar) (sizeof(ar)/sizeof((ar)[0]))
/** Macro used to compute the minimum of two integral values. */
#define CRY_MIN(a, b) (((a) < (b)) ? (a) : (b))
/** Macro used to compute the maximum of two integral values. */
#define CRY_MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif /* _CRY_MISC_H_ */
......@@ -9,7 +9,8 @@ LDLIBS := $(LIBCRY)
TESTS := version_test \
base64_test \
des_test \
aes_test
aes_test \
cbc_test
.PHONY: all clean
......
/*
* Copyright (c) 2013, Davide Galassi. All rights reserved.
*
* This file is part of CRY software.
*
* CRY is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CRY; if not, see <http://www.gnu/licenses/>.
*/
#include <cry.h>
#include <stdio.h>
#include <string.h>
static const struct cry_ciph_itf aes_itf = {
.init = NULL,
.clean = NULL,
.key_set = (cry_ciph_key_set_f) cry_aes_key_set,
.encrypt = (cry_ciph_encrypt_f) cry_aes_encrypt,
.decrypt = (cry_ciph_decrypt_f) cry_aes_decrypt
};
void cry_aes_128_cbc_encrypt(unsigned char *dst, const unsigned char *src,
unsigned int size, unsigned char *key,
unsigned char *iv)
{
struct cry_aes_ctx aes;
struct cry_cbc_ctx cbc;
cbc.ciph_itf = &aes_itf;
cbc.ciph_ctx = &aes;
cry_cbc_key_set(&cbc, key, 16);
cry_cbc_iv_set(&cbc, iv, 16);
cry_cbc_encrypt(&cbc, dst, src, size);
}
void cry_aes_128_cbc_decrypt(unsigned char *dst, const unsigned char *src,
unsigned int size, unsigned char *key,
unsigned char *iv)
{
struct cry_aes_ctx aes;
struct cry_cbc_ctx cbc;
cbc.ciph_itf = &aes_itf;
cbc.ciph_ctx = &aes;
cry_cbc_key_set(&cbc, key, 16);
cry_cbc_iv_set(&cbc, iv, 16);
cry_cbc_decrypt(&cbc, dst, src, size);
}
int main(void)
{
char buf[128];
char *msg = "CRY is free software: you can redistribute it and/or modify";
char key[] = { 0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13,14,15 };
char iv[] = { 0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13,14,15 };
int msglen = strlen(msg);
printf("Msg len: %d\n", msglen);
printf("AES-128-CBC\n");
memset(buf, 0, sizeof(buf));
cry_aes_128_cbc_encrypt(buf, msg, msglen, key, iv);
cry_aes_128_cbc_decrypt(buf, buf, msglen, key, iv);
printf("%.*s\n", msglen, buf);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment