yuzu/externals/libressl/crypto/modes/cts128.c

268 lines
5.9 KiB
C
Raw Normal View History

2020-12-28 19:15:37 +04:00
/* $OpenBSD: cts128.c,v 1.5 2015/07/19 18:27:26 miod Exp $ */
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Rights for redistribution and usage in source and binary
* forms are granted according to the OpenSSL license.
*/
#include <openssl/crypto.h>
#include "modes_lcl.h"
#include <string.h>
#ifndef MODES_DEBUG
# ifndef NDEBUG
# define NDEBUG
# endif
#endif
/*
* Trouble with Ciphertext Stealing, CTS, mode is that there is no
* common official specification, but couple of cipher/application
* specific ones: RFC2040 and RFC3962. Then there is 'Proposal to
* Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which
* deviates from mentioned RFCs. Most notably it allows input to be
* of block length and it doesn't flip the order of the last two
* blocks. CTS is being discussed even in ECB context, but it's not
* adopted for any known application. This implementation provides
* two interfaces: one compliant with above mentioned RFCs and one
* compliant with the NIST proposal, both extending CBC mode.
*/
size_t CRYPTO_cts128_encrypt_block(const unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char ivec[16], block128_f block)
{ size_t residue, n;
if (len <= 16) return 0;
if ((residue=len%16) == 0) residue = 16;
len -= residue;
CRYPTO_cbc128_encrypt(in,out,len,key,ivec,block);
in += len;
out += len;
for (n=0; n<residue; ++n)
ivec[n] ^= in[n];
(*block)(ivec,ivec,key);
memcpy(out,out-16,residue);
memcpy(out-16,ivec,16);
return len+residue;
}
size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char ivec[16], block128_f block)
{ size_t residue, n;
if (len < 16) return 0;
residue=len%16;
len -= residue;
CRYPTO_cbc128_encrypt(in,out,len,key,ivec,block);
if (residue==0) return len;
in += len;
out += len;
for (n=0; n<residue; ++n)
ivec[n] ^= in[n];
(*block)(ivec,ivec,key);
memcpy(out-16+residue,ivec,16);
return len+residue;
}
size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char ivec[16], cbc128_f cbc)
{ size_t residue;
union { size_t align; unsigned char c[16]; } tmp;
if (len <= 16) return 0;
if ((residue=len%16) == 0) residue = 16;
len -= residue;
(*cbc)(in,out,len,key,ivec,1);
in += len;
out += len;
memset(tmp.c,0,sizeof(tmp));
memcpy(tmp.c,in,residue);
memcpy(out,out-16,residue);
(*cbc)(tmp.c,out-16,16,key,ivec,1);
return len+residue;
}
size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char ivec[16], cbc128_f cbc)
{ size_t residue;
union { size_t align; unsigned char c[16]; } tmp;
if (len < 16) return 0;
residue=len%16;
len -= residue;
(*cbc)(in,out,len,key,ivec,1);
if (residue==0) return len;
in += len;
out += len;
memset(tmp.c,0,sizeof(tmp));
memcpy(tmp.c,in,residue);
(*cbc)(tmp.c,out-16+residue,16,key,ivec,1);
return len+residue;
}
size_t CRYPTO_cts128_decrypt_block(const unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char ivec[16], block128_f block)
{ size_t residue, n;
union { size_t align; unsigned char c[32]; } tmp;
if (len<=16) return 0;
if ((residue=len%16) == 0) residue = 16;
len -= 16+residue;
if (len) {
CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block);
in += len;
out += len;
}
(*block)(in,tmp.c+16,key);
memcpy(tmp.c,tmp.c+16,16);
memcpy(tmp.c,in+16,residue);
(*block)(tmp.c,tmp.c,key);
for(n=0; n<16; ++n) {
unsigned char c = in[n];
out[n] = tmp.c[n] ^ ivec[n];
ivec[n] = c;
}
for(residue+=16; n<residue; ++n)
out[n] = tmp.c[n] ^ in[n];
return 16+len+residue;
}
size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char ivec[16], block128_f block)
{ size_t residue, n;
union { size_t align; unsigned char c[32]; } tmp;
if (len<16) return 0;
residue=len%16;
if (residue==0) {
CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block);
return len;
}
len -= 16+residue;
if (len) {
CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block);
in += len;
out += len;
}
(*block)(in+residue,tmp.c+16,key);
memcpy(tmp.c,tmp.c+16,16);
memcpy(tmp.c,in,residue);
(*block)(tmp.c,tmp.c,key);
for(n=0; n<16; ++n) {
unsigned char c = in[n];
out[n] = tmp.c[n] ^ ivec[n];
ivec[n] = in[n+residue];
tmp.c[n] = c;
}
for(residue+=16; n<residue; ++n)
out[n] = tmp.c[n] ^ tmp.c[n-16];
return 16+len+residue;
}
size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char ivec[16], cbc128_f cbc)
{ size_t residue;
union { size_t align; unsigned char c[32]; } tmp;
if (len<=16) return 0;
if ((residue=len%16) == 0) residue = 16;
len -= 16+residue;
if (len) {
(*cbc)(in,out,len,key,ivec,0);
in += len;
out += len;
}
memset(tmp.c,0,sizeof(tmp));
/* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */
(*cbc)(in,tmp.c,16,key,tmp.c+16,0);
memcpy(tmp.c,in+16,residue);
(*cbc)(tmp.c,tmp.c,32,key,ivec,0);
memcpy(out,tmp.c,16+residue);
return 16+len+residue;
}
size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char ivec[16], cbc128_f cbc)
{ size_t residue;
union { size_t align; unsigned char c[32]; } tmp;
if (len<16) return 0;
residue=len%16;
if (residue==0) {
(*cbc)(in,out,len,key,ivec,0);
return len;
}
len -= 16+residue;
if (len) {
(*cbc)(in,out,len,key,ivec,0);
in += len;
out += len;
}
memset(tmp.c,0,sizeof(tmp));
/* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */
(*cbc)(in+residue,tmp.c,16,key,tmp.c+16,0);
memcpy(tmp.c,in,residue);
(*cbc)(tmp.c,tmp.c,32,key,ivec,0);
memcpy(out,tmp.c,16+residue);
return 16+len+residue;
}