"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/h235/h235crypto.cxx" between
h323plus-1_26_9.tar.gz and h323plus-1_27_0.tar.gz

About: H.323 Plus offers libraries for voice (VoIP) and videoconferencing using H.323.

h235crypto.cxx  (h323plus-1_26_9):h235crypto.cxx  (h323plus-1_27_0)
/* /*
* h235crypto.cxx * h235crypto.cxx
* *
* H.235 crypto engine class. * H.235 crypto engine class.
* *
* H323Plus library * H323Plus library
* *
* Copyright (c) 2012 Jan Willamowius * Copyright (c) 2012-2018 Jan Willamowius
* *
* The contents of this file are subject to the Mozilla Public License * The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in * Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at * compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/ * http://www.mozilla.org/MPL/
* *
* Alternatively, the contents of this file may be used under the terms * Alternatively, the contents of this file may be used under the terms
* of the General Public License (the "GNU License"), in which case the * of the General Public License (the "GNU License"), in which case the
* provisions of GNU License are applicable instead of those * provisions of GNU License are applicable instead of those
* above. If you wish to allow use of your version of this file only * above. If you wish to allow use of your version of this file only
skipping to change at line 38 skipping to change at line 38
* the License for the specific language governing rights and limitations * the License for the specific language governing rights and limitations
* under the License. * under the License.
* *
* *
* The Initial Developer of the Original Code is Jan Willamowius. * The Initial Developer of the Original Code is Jan Willamowius.
* *
* $Id$ * $Id$
* *
*/ */
#include <string.h>
#include <ptlib.h> #include <ptlib.h>
#include "openh323buildopts.h" #include "openh323buildopts.h"
#ifdef H323_H235 #ifdef H323_H235
#include "h323con.h" #include "h323con.h"
#include "h235/h235crypto.h" #include "h235/h235crypto.h"
#include "h235/h235caps.h" #include "h235/h235caps.h"
#include "h235/h235support.h" #include "h235/h235support.h"
extern "C" {
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include <openssl/rand.h> #include <openssl/rand.h>
}
#include "rtp.h" #include "rtp.h"
#ifdef H323_H235_AES256 #ifdef H323_H235_AES256
#if _WIN32 #if _WIN32
#pragma message("AES256 Encryption Enabled. Software may be subject to US export restrictions. http://www.bis.doc.gov/encryption/") #pragma message("AES256 Encryption Enabled. Software may be subject to US export restrictions. http://www.bis.doc.gov/encryption/")
#else #else
#warning("AES256 Encryption Enabled. Software may be subject to US export restri ctions. http://www.bis.doc.gov/encryption/") #warning("AES256 Encryption Enabled. Software may be subject to US export restri ctions. http://www.bis.doc.gov/encryption/")
#endif #endif
#endif #endif
// the IV sequence is always 6 bytes long (2 bytes seq number + 4 bytes timestam p) // the IV sequence is always 6 bytes long (2 bytes seq number + 4 bytes timestam p)
const unsigned int IV_SEQUENCE_LEN = 6; const unsigned int IV_SEQUENCE_LEN = 6;
// ciphertext stealing code based on a OpenSSL patch by An-Cheng Huang #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
inline const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx)
{
return ctx->iv;
}
#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
// Ciphertext stealing (CTS) code based on an OpenSSL patch by An-Cheng Huang
// Note: This ciphertext stealing implementation doesn't seem to always produce // Note: This ciphertext stealing implementation doesn't seem to always produce
// compatible results, avoid when encrypting: // compatible results, avoid when encrypting.
// EncryptUpdate, DecryptUpdate and DecryptFinalRelaxed implementation is based
// on the code from OpenSSL. These functions are implemented here for the sake o
f
// a workaround for some broken terminals in DecryptFinalRelaxed.
H235CryptoHelper::H235CryptoHelper()
{
memset(buf, 0, sizeof(buf));
memset(final_buf, 0, sizeof(final_buf));
Reset();
}
int EVP_EncryptUpdate_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, void H235CryptoHelper::Reset()
{
buf_len = 0;
final_used = 0;
}
int H235CryptoHelper::EncryptUpdateCTS(EVP_CIPHER_CTX *ctx, unsigned char *out,
int *outl,
const unsigned char *in, int inl) const unsigned char *in, int inl)
{ {
int bl = ctx->cipher->block_size; const int bl = EVP_CIPHER_CTX_block_size(ctx);
OPENSSL_assert(bl <= (int)sizeof(ctx->buf)); OPENSSL_assert(bl <= (int)sizeof(buf));
*outl = 0; *outl = 0;
if ((ctx->buf_len + inl) <= bl) { if (inl <= 0)
return inl == 0;
if ((buf_len + inl) <= bl) {
/* new plaintext is no more than 1 block */ /* new plaintext is no more than 1 block */
/* copy the in data into the buffer and return */ /* copy the in data into the buffer and return */
memcpy(&(ctx->buf[ctx->buf_len]), in, inl); memcpy(&(buf[buf_len]), in, inl);
ctx->buf_len += inl; buf_len += inl;
*outl = 0;
return 1; return 1;
} }
/* more than 1 block of new plaintext available */ /* more than 1 block of new plaintext available */
/* encrypt the previous plaintext, if any */ /* encrypt the previous plaintext, if any */
if (ctx->final_used) { if (final_used) {
if (!(ctx->cipher->do_cipher(ctx, out, ctx->final, bl))) { if (!(EVP_Cipher(ctx, out, final_buf, bl))) {
return 0; return 0;
} }
out += bl; out += bl;
*outl += bl; *outl += bl;
ctx->final_used = 0; final_used = 0;
} }
/* we already know ctx->buf_len + inl must be > bl */ /* we already know buf_len + inl must be > bl */
memcpy(&(ctx->buf[ctx->buf_len]), in, (bl - ctx->buf_len)); memcpy(&(buf[buf_len]), in, (bl - buf_len));
in += (bl - ctx->buf_len); in += (bl - buf_len);
inl -= (bl - ctx->buf_len); inl -= (bl - buf_len);
ctx->buf_len = bl; buf_len = bl;
if (inl <= bl) { if (inl <= bl) {
memcpy(ctx->final, ctx->buf, bl); memcpy(final_buf, buf, bl);
ctx->final_used = 1; final_used = 1;
memcpy(ctx->buf, in, inl); memcpy(buf, in, inl);
ctx->buf_len = inl; buf_len = inl;
return 1; return 1;
} else { } else {
if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) { if (!(EVP_Cipher(ctx, out, buf, bl))) {
return 0; return 0;
} }
out += bl; out += bl;
*outl += bl; *outl += bl;
ctx->buf_len = 0; buf_len = 0;
int leftover = inl & ctx->block_mask; int leftover = inl & (bl - 1);
if (leftover) { if (leftover) {
inl -= (bl + leftover); inl -= (bl + leftover);
memcpy(ctx->buf, &(in[(inl + bl)]), leftover); memcpy(buf, &(in[(inl + bl)]), leftover);
ctx->buf_len = leftover; buf_len = leftover;
} else { } else {
inl -= (2 * bl); inl -= (2 * bl);
memcpy(ctx->buf, &(in[(inl + bl)]), bl); memcpy(buf, &(in[(inl + bl)]), bl);
ctx->buf_len = bl; buf_len = bl;
} }
memcpy(ctx->final, &(in[inl]), bl); memcpy(final_buf, &(in[inl]), bl);
ctx->final_used = 1; final_used = 1;
if (!(ctx->cipher->do_cipher(ctx, out, in, inl))) { if (!(EVP_Cipher(ctx, out, in, inl))) {
return 0; return 0;
} }
out += inl; out += inl;
*outl += inl; *outl += inl;
} }
return 1; return 1;
} }
#if PTLIB_VER >= 2130 int H235CryptoHelper::EncryptFinalCTS(EVP_CIPHER_CTX *ctx, unsigned char *out, i
int EVP_EncryptFinal_ctsA(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) nt *outl)
#else
int EVP_EncryptFinal_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
#endif
{ {
unsigned char tmp[EVP_MAX_BLOCK_LENGTH]; unsigned char tmp[EVP_MAX_BLOCK_LENGTH];
int bl = ctx->cipher->block_size; const int bl = EVP_CIPHER_CTX_block_size(ctx);
int leftover = 0; int leftover = 0;
*outl = 0; *outl = 0;
if (!ctx->final_used) { if (!final_used) {
PTRACE(1, "H235\tCTS Error: expecting previous ciphertext"); PTRACE(1, "H235\tCTS Error: expecting previous ciphertext");
return 0; return 0;
} }
if (ctx->buf_len == 0) { if (buf_len == 0) {
PTRACE(1, "H235\tCTS Error: expecting previous plaintext"); PTRACE(1, "H235\tCTS Error: expecting previous plaintext");
return 0; return 0;
} }
/* handle leftover bytes */ /* handle leftover bytes */
leftover = ctx->buf_len; leftover = buf_len;
switch (EVP_CIPHER_CTX_mode(ctx)) { switch (EVP_CIPHER_CTX_mode(ctx)) {
case EVP_CIPH_ECB_MODE: { case EVP_CIPH_ECB_MODE: {
/* encrypt => C_{n} plus C' */ /* encrypt => C_{n} plus C' */
if (!(ctx->cipher->do_cipher(ctx, tmp, ctx->final, bl))) { if (!(EVP_Cipher(ctx, tmp, final_buf, bl))) {
return 0; return 0;
} }
/* P_n plus C' */ /* P_n plus C' */
memcpy(&(ctx->buf[leftover]), &(tmp[leftover]), (bl - leftover)); memcpy(&(buf[leftover]), &(tmp[leftover]), (bl - leftover));
/* encrypt => C_{n-1} */ /* encrypt => C_{n-1} */
if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) { if (!(EVP_Cipher(ctx, out, buf, bl))) {
return 0; return 0;
} }
memcpy((out + bl), tmp, leftover); memcpy((out + bl), tmp, leftover);
*outl += (bl + leftover); *outl += (bl + leftover);
return 1; return 1;
} }
case EVP_CIPH_CBC_MODE: { case EVP_CIPH_CBC_MODE: {
/* encrypt => C_{n} plus C' */ /* encrypt => C_{n} plus C' */
if (!(ctx->cipher->do_cipher(ctx, tmp, ctx->final, bl))) { if (!(EVP_Cipher(ctx, tmp, final_buf, bl))) {
return 0; return 0;
} }
/* P_n plus 0s */ /* P_n plus 0s */
memset(&(ctx->buf[leftover]), 0, (bl - leftover)); memset(&(buf[leftover]), 0, (bl - leftover));
/* note that in cbc encryption, plaintext will be xor'ed with the pr evious /* note that in cbc encryption, plaintext will be xor'ed with the pr evious
* ciphertext, which is what we want. * ciphertext, which is what we want.
*/ */
/* encrypt => C_{n-1} */ /* encrypt => C_{n-1} */
if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) { if (!(EVP_Cipher(ctx, out, buf, bl))) {
return 0; return 0;
} }
memcpy((out + bl), tmp, leftover); memcpy((out + bl), tmp, leftover);
*outl += (bl + leftover); *outl += (bl + leftover);
return 1; return 1;
} }
default: default: {
PTRACE(1, "H235\tCTS Error: unsupported mode"); PTRACE(1, "H235\tCTS Error: unsupported mode");
return 0; return 0;
}
} }
} }
int EVP_DecryptUpdate_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, int H235CryptoHelper::EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
const unsigned char *in, int inl) const unsigned char *in, int inl)
{ {
return EVP_EncryptUpdate_cts(ctx, out, outl, in, inl); *outl = 0;
if (inl <= 0)
return inl == 0;
const int bl = EVP_CIPHER_CTX_block_size(ctx);
OPENSSL_assert(bl <= (int)sizeof(buf));
if (buf_len == 0 && (inl & (bl - 1)) == 0) {
if (!(EVP_Cipher(ctx, out, in, inl)))
return 0;
*outl = inl;
return 1;
}
int i = buf_len;
if (i != 0) {
if (i + inl < bl) {
memcpy(buf + i, in, inl);
buf_len += inl;
return 1;
} else {
int j = bl - i;
memcpy(buf + i, in, j);
if (!(EVP_Cipher(ctx, out, buf, bl)))
return 0;
inl -= j;
in += j;
out += bl;
*outl = bl;
}
}
i = inl & (bl - 1);
inl -= i;
if (inl > 0) {
if (!(EVP_Cipher(ctx, out, in, inl)))
return 0;
*outl += inl;
}
if (i != 0)
memcpy(buf, in + inl, i);
buf_len = i;
return 1;
} }
int EVP_DecryptFinal_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) int H235CryptoHelper::DecryptUpdateCTS(EVP_CIPHER_CTX *ctx, unsigned char *out,
int *outl,
const unsigned char *in, int inl)
{
return EncryptUpdateCTS(ctx, out, outl, in, inl);
}
int H235CryptoHelper::DecryptFinalCTS(EVP_CIPHER_CTX *ctx, unsigned char *out, i
nt *outl)
{ {
unsigned char tmp[EVP_MAX_BLOCK_LENGTH]; unsigned char tmp[EVP_MAX_BLOCK_LENGTH];
int bl = ctx->cipher->block_size; const int bl = EVP_CIPHER_CTX_block_size(ctx);
int leftover = 0; int leftover = 0;
*outl = 0; *outl = 0;
if (!ctx->final_used) { if (!final_used) {
PTRACE(1, "H235\tCTS Error: expecting previous ciphertext"); PTRACE(1, "H235\tCTS Error: expecting previous ciphertext");
return 0; return 0;
} }
if (ctx->buf_len == 0) { if (buf_len == 0) {
PTRACE(1, "H235\tCTS Error: expecting previous ciphertext"); PTRACE(1, "H235\tCTS Error: expecting previous ciphertext");
return 0; return 0;
} }
/* handle leftover bytes */ /* handle leftover bytes */
leftover = ctx->buf_len; leftover = buf_len;
switch (EVP_CIPHER_CTX_mode(ctx)) { switch (EVP_CIPHER_CTX_mode(ctx)) {
case EVP_CIPH_ECB_MODE: { case EVP_CIPH_ECB_MODE: {
/* decrypt => P_n plus C' */ /* decrypt => P_n plus C' */
if (!(ctx->cipher->do_cipher(ctx, tmp, ctx->final, bl))) { if (!(EVP_Cipher(ctx, tmp, final_buf, bl))) {
return 0; return 0;
} }
/* C_n plus C' */ /* C_n plus C' */
memcpy(&(ctx->buf[leftover]), &(tmp[leftover]), (bl - leftover)); memcpy(&(buf[leftover]), &(tmp[leftover]), (bl - leftover));
/* decrypt => P_{n-1} */ /* decrypt => P_{n-1} */
if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) { if (!(EVP_Cipher(ctx, out, buf, bl))) {
return 0; return 0;
} }
memcpy((out + bl), tmp, leftover); memcpy((out + bl), tmp, leftover);
*outl += (bl + leftover); *outl += (bl + leftover);
return 1; return 1;
} }
case EVP_CIPH_CBC_MODE: { case EVP_CIPH_CBC_MODE: {
int i = 0; int i = 0;
unsigned char C_n_minus_2[EVP_MAX_BLOCK_LENGTH]; unsigned char C_n_minus_2[EVP_MAX_BLOCK_LENGTH];
memcpy(C_n_minus_2, ctx->iv, bl); memcpy(C_n_minus_2, EVP_CIPHER_CTX_iv(ctx), bl);
/* C_n plus 0s in ctx->buf */ /* C_n plus 0s in buf */
memset(&(ctx->buf[leftover]), 0, (bl - leftover)); memset(&(buf[leftover]), 0, (bl - leftover));
/* ctx->final is C_{n-1} */ /* final_buf is C_{n-1} */
/* decrypt => (P_n plus C')'' */ /* decrypt => (P_n plus C')'' */
if (!(ctx->cipher->do_cipher(ctx, tmp, ctx->final, bl))) { if (!(EVP_Cipher(ctx, tmp, final_buf, bl))) {
return 0; return 0;
} }
/* XOR'ed with C_{n-2} => (P_n plus C')' */ /* XOR'ed with C_{n-2} => (P_n plus C')' */
for (i = 0; i < bl; i++) { for (i = 0; i < bl; i++) {
tmp[i] = tmp[i] ^ C_n_minus_2[i]; tmp[i] = tmp[i] ^ C_n_minus_2[i];
} }
/* XOR'ed with (C_n plus 0s) => P_n plus C' */ /* XOR'ed with (C_n plus 0s) => P_n plus C' */
for (i = 0; i < bl; i++) { for (i = 0; i < bl; i++) {
tmp[i] = tmp[i] ^ ctx->buf[i]; tmp[i] = tmp[i] ^ buf[i];
} }
/* C_n plus C' in ctx->buf */ /* C_n plus C' in buf */
memcpy(&(ctx->buf[leftover]), &(tmp[leftover]), (bl - leftover)); memcpy(&(buf[leftover]), &(tmp[leftover]), (bl - leftover));
/* decrypt => P_{n-1}'' */ /* decrypt => P_{n-1}'' */
if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) { if (!(EVP_Cipher(ctx, out, buf, bl))) {
return 0; return 0;
} }
/* XOR'ed with C_{n-1} => P_{n-1}' */ /* XOR'ed with C_{n-1} => P_{n-1}' */
for (i = 0; i < bl; i++) { for (i = 0; i < bl; i++) {
out[i] = out[i] ^ ctx->final[i]; out[i] = out[i] ^ final_buf[i];
} }
/* XOR'ed with C_{n-2} => P_{n-1} */ /* XOR'ed with C_{n-2} => P_{n-1} */
for (i = 0; i < bl; i++) { for (i = 0; i < bl; i++) {
out[i] = out[i] ^ C_n_minus_2[i]; out[i] = out[i] ^ C_n_minus_2[i];
} }
memcpy((out + bl), tmp, leftover); memcpy((out + bl), tmp, leftover);
*outl += (bl + leftover); *outl += (bl + leftover);
return 1; return 1;
} }
default: default: {
PTRACE(1, "H235\tCTS Error: unsupported mode"); PTRACE(1, "H235\tCTS Error: unsupported mode");
return 0; return 0;
}
}
}
int H235CryptoHelper::DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int
*outl,
const unsigned char *in, int inl)
{
if (inl <= 0) {
*outl = 0;
return inl == 0;
}
if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_NO_PADDING))
return EncryptUpdate(ctx, out, outl, in, inl);
const int bl = EVP_CIPHER_CTX_block_size(ctx);
OPENSSL_assert(bl <= (int)sizeof(final_buf));
int fix_len = 0;
if (final_used) {
memcpy(out, final_buf, bl);
out += bl;
fix_len = 1;
}
if (!EncryptUpdate(ctx, out, outl, in, inl))
return 0;
/*
* if we have 'decrypted' a multiple of block size, make sure we have a
* copy of this last block
*/
if (bl > 1 && !buf_len) {
*outl -= bl;
final_used = 1;
memcpy(final_buf, out + *outl, bl);
} }
else
final_used = 0;
if (fix_len)
*outl += bl;
return 1;
} }
int EVP_DecryptFinal_relaxed(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) int H235CryptoHelper::DecryptFinalRelaxed(EVP_CIPHER_CTX *ctx, unsigned char *ou t, int *outl)
{ {
unsigned int b = 0;
*outl = 0; *outl = 0;
b=ctx->cipher->block_size; if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_NO_PADDING)) {
if (ctx->flags & EVP_CIPH_NO_PADDING) { if(buf_len) {
if(ctx->buf_len) {
PTRACE(1, "H235\tDecrypt error: data not a multiple of block length" ); PTRACE(1, "H235\tDecrypt error: data not a multiple of block length" );
return 0; return 0;
} }
*outl = 0;
return 1; return 1;
} }
if (b > 1) {
if (ctx->buf_len || !ctx->final_used) { const int bl = EVP_CIPHER_CTX_block_size(ctx);
if (bl > 1) {
if (buf_len || !final_used) {
PTRACE(1, "H235\tDecrypt error: wrong final block length"); PTRACE(1, "H235\tDecrypt error: wrong final block length");
return(0); return 0;
} }
OPENSSL_assert(b <= sizeof ctx->final); OPENSSL_assert(bl <= (int)sizeof(final_buf));
int n=ctx->final[b-1]; int n = final_buf[bl - 1];
if (n == 0 || n > (int)b) { if (n == 0 || n > bl) {
PTRACE(1, "H235\tDecrypt error: bad decrypt"); PTRACE(1, "H235\tDecrypt error: bad decrypt");
return(0); return 0;
} }
// Polycom endpoints (eg. m100 and PVX) don't fill the padding propperly , so we have to disable this check // Polycom endpoints (eg. m100 and PVX) don't fill the padding propperly , so we have to disable this check
/* /*
for (int i=0; i<n; i++) { for (int i=0; i<n; i++) {
if (ctx->final[--b] != n) { if (final_buf[bl - i] != n) {
PTRACE(1, "H235\tDecrypt error: incorrect padding"); PTRACE(1, "H235\tDecrypt error: incorrect padding");
return(0); return 0;
} }
} }
*/ */
n=ctx->cipher->block_size-n; n = bl - n;
for (int i=0; i<n; i++) memcpy(out, final_buf, n);
out[i]=ctx->final[i]; *outl = n;
*outl=n;
} }
else
*outl=0; return 1;
return(1);
} }
H235CryptoEngine::H235CryptoEngine(const PString & algorithmOID) H235CryptoEngine::H235CryptoEngine(const PString & algorithmOID)
: m_algorithmOID(algorithmOID), m_operationCnt(0), m_initialised(false), : m_encryptCtx(NULL), m_decryptCtx(NULL),
m_algorithmOID(algorithmOID), m_operationCnt(0), m_initialised(false),
m_enc_blockSize(0), m_enc_ivLength(0), m_dec_blockSize(0), m_dec_ivLength(0) m_enc_blockSize(0), m_enc_ivLength(0), m_dec_blockSize(0), m_dec_ivLength(0)
{ {
} }
H235CryptoEngine::H235CryptoEngine(const PString & algorithmOID, const PBYTEArra y & key) H235CryptoEngine::H235CryptoEngine(const PString & algorithmOID, const PBYTEArra y & key)
: m_algorithmOID(algorithmOID), m_operationCnt(0), m_initialised(false), : m_encryptCtx(NULL), m_decryptCtx(NULL),
m_algorithmOID(algorithmOID), m_operationCnt(0), m_initialised(false),
m_enc_blockSize(0), m_enc_ivLength(0), m_dec_blockSize(0), m_dec_ivLength(0) m_enc_blockSize(0), m_enc_ivLength(0), m_dec_blockSize(0), m_dec_ivLength(0)
{ {
SetKey(key); SetKey(key);
} }
H235CryptoEngine::~H235CryptoEngine() H235CryptoEngine::~H235CryptoEngine()
{ {
if (m_initialised) { if (m_encryptCtx != NULL)
EVP_CIPHER_CTX_cleanup(&m_encryptCtx); EVP_CIPHER_CTX_free(m_encryptCtx);
EVP_CIPHER_CTX_cleanup(&m_decryptCtx); if (m_decryptCtx != NULL)
} EVP_CIPHER_CTX_free(m_decryptCtx);
} }
void H235CryptoEngine::SetKey(PBYTEArray key) void H235CryptoEngine::SetKey(PBYTEArray key)
{ {
const EVP_CIPHER * cipher = NULL; const EVP_CIPHER * cipher = NULL;
if (m_algorithmOID == ID_AES128) { if (m_algorithmOID == ID_AES128) {
cipher = EVP_aes_128_cbc(); cipher = EVP_aes_128_cbc();
#ifdef H323_H235_AES256 #ifdef H323_H235_AES256
} else if (m_algorithmOID == ID_AES192) { } else if (m_algorithmOID == ID_AES192) {
cipher = EVP_aes_192_cbc(); cipher = EVP_aes_192_cbc();
} else if (m_algorithmOID == ID_AES256) { } else if (m_algorithmOID == ID_AES256) {
cipher = EVP_aes_256_cbc(); cipher = EVP_aes_256_cbc();
#endif #endif
} else { } else {
PTRACE(1, "H235\tUnsupported algorithm " << m_algorithmOID); PTRACE(1, "H235\tUnsupported algorithm " << m_algorithmOID);
return; return;
} }
EVP_CIPHER_CTX_init(&m_encryptCtx); m_initialised = false;
EVP_EncryptInit_ex(&m_encryptCtx, cipher, NULL, key.GetPointer(), NULL);
m_enc_blockSize = EVP_CIPHER_CTX_block_size(&m_encryptCtx); if (m_encryptCtx == NULL) {
m_enc_ivLength = EVP_CIPHER_CTX_iv_length(&m_encryptCtx); m_encryptCtx = EVP_CIPHER_CTX_new();
if (m_encryptCtx == NULL) {
EVP_CIPHER_CTX_init(&m_decryptCtx); PTRACE(1, "H235\tFailed to allocate EVP encrypt context");
EVP_DecryptInit_ex(&m_decryptCtx, cipher, NULL, key.GetPointer(), NULL); return;
m_dec_blockSize = EVP_CIPHER_CTX_block_size(&m_decryptCtx); }
m_dec_ivLength = EVP_CIPHER_CTX_iv_length(&m_decryptCtx); } else {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_CIPHER_CTX_cleanup(m_encryptCtx);
EVP_CIPHER_CTX_init(m_encryptCtx);
#else
EVP_CIPHER_CTX_reset(m_encryptCtx);
#endif
}
EVP_EncryptInit_ex(m_encryptCtx, cipher, NULL, key.GetPointer(), NULL);
m_enc_blockSize = EVP_CIPHER_CTX_block_size(m_encryptCtx);
m_enc_ivLength = EVP_CIPHER_CTX_iv_length(m_encryptCtx);
m_encryptHelper.Reset();
if (m_decryptCtx == NULL) {
m_decryptCtx = EVP_CIPHER_CTX_new();
if (m_decryptCtx == NULL) {
PTRACE(1, "H235\tFailed to allocate EVP decrypt context");
return;
}
} else {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_CIPHER_CTX_cleanup(m_decryptCtx);
EVP_CIPHER_CTX_init(m_decryptCtx);
#else
EVP_CIPHER_CTX_reset(m_decryptCtx);
#endif
}
EVP_DecryptInit_ex(m_decryptCtx, cipher, NULL, key.GetPointer(), NULL);
m_dec_blockSize = EVP_CIPHER_CTX_block_size(m_decryptCtx);
m_dec_ivLength = EVP_CIPHER_CTX_iv_length(m_decryptCtx);
m_decryptHelper.Reset();
m_operationCnt = 0; m_operationCnt = 0;
m_initialised = true; m_initialised = true;
} }
void H235CryptoEngine::SetIV(unsigned char * iv, unsigned char * ivSequence, uns igned ivLen) void H235CryptoEngine::SetIV(unsigned char * iv, unsigned char * ivSequence, uns igned ivLen)
{ {
// fill iv by repeating ivSequence until block size is reached // fill iv by repeating ivSequence until block size is reached
if (ivSequence) { if (ivSequence) {
for (unsigned i = 0; i < (ivLen / IV_SEQUENCE_LEN); i++) { for (unsigned i = 0; i < (ivLen / IV_SEQUENCE_LEN); i++) {
skipping to change at line 415 skipping to change at line 567
PBYTEArray H235CryptoEngine::Encrypt(const PBYTEArray & _data, unsigned char * i vSequence, bool & rtpPadding) PBYTEArray H235CryptoEngine::Encrypt(const PBYTEArray & _data, unsigned char * i vSequence, bool & rtpPadding)
{ {
if (!m_initialised) if (!m_initialised)
return PBYTEArray(); return PBYTEArray();
PBYTEArray & data = *(PRemoveConst(PBYTEArray, &_data)); PBYTEArray & data = *(PRemoveConst(PBYTEArray, &_data));
unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH];
// max ciphertext len for a n bytes of plaintext is n + BLOCK_SIZE -1 bytes // max ciphertext len for a n bytes of plaintext is n + BLOCK_SIZE -1 bytes
int ciphertext_len = data.GetSize() + EVP_CIPHER_CTX_block_size(&m_encryptCt x); int ciphertext_len = data.GetSize() + m_enc_blockSize;
int final_len = 0; int final_len = 0;
PBYTEArray ciphertext(ciphertext_len); PBYTEArray ciphertext(ciphertext_len);
SetIV(iv, ivSequence, EVP_CIPHER_CTX_iv_length(&m_encryptCtx)); SetIV(iv, ivSequence, m_enc_ivLength);
EVP_EncryptInit_ex(&m_encryptCtx, NULL, NULL, NULL, iv); EVP_EncryptInit_ex(m_encryptCtx, NULL, NULL, NULL, iv);
m_encryptHelper.Reset();
// always use padding, because our ciphertext stealing implementation // always use padding, because our ciphertext stealing implementation
// doesn't seem to produce compatible results // doesn't seem to produce compatible results
//rtpPadding = (data.GetSize() < EVP_CIPHER_CTX_block_size(&m_encryptCtx)); //rtpPadding = (data.GetSize() < m_enc_blockSize); // not interoperable!
// not interoperable! rtpPadding = (data.GetSize() % m_enc_blockSize > 0);
rtpPadding = (data.GetSize() % EVP_CIPHER_CTX_block_size(&m_encryptCtx) > 0) EVP_CIPHER_CTX_set_padding(m_encryptCtx, rtpPadding ? 1 : 0);
;
EVP_CIPHER_CTX_set_padding(&m_encryptCtx, rtpPadding ? 1 : 0);
if (!rtpPadding && (data.GetSize() % EVP_CIPHER_CTX_block_size(&m_encryptCtx ) > 0)) { if (!rtpPadding && (data.GetSize() % m_enc_blockSize > 0)) {
// use cyphertext stealing // use cyphertext stealing
if (!EVP_EncryptUpdate_cts(&m_encryptCtx, ciphertext.GetPointer(), &ciph if (!m_encryptHelper.EncryptUpdateCTS(m_encryptCtx, ciphertext.GetPointe
ertext_len, data.GetPointer(), data.GetSize())) { r(), &ciphertext_len, data.GetPointer(), data.GetSize())) {
PTRACE(1, "H235\tEVP_EncryptUpdate_cts() failed"); PTRACE(1, "H235\tEncryptUpdateCTS() failed");
} }
#if PTLIB_VER >= 2130 if (!m_encryptHelper.EncryptFinalCTS(m_encryptCtx, ciphertext.GetPointer
if (!EVP_EncryptFinal_ctsA(&m_encryptCtx, ciphertext.GetPointer() + ciph () + ciphertext_len, &final_len)) {
ertext_len, &final_len)) { PTRACE(1, "H235\tEncryptFinalCTS() failed");
#else
if (!EVP_EncryptFinal_cts(&m_encryptCtx, ciphertext.GetPointer() + ciphe
rtext_len, &final_len)) {
#endif
PTRACE(1, "H235\tEVP_EncryptFinal_cts() failed");
} }
} else { } else {
/* update ciphertext, ciphertext_len is filled with the length of cipher text generated, /* update ciphertext, ciphertext_len is filled with the length of cipher text generated,
*len is the size of plaintext in bytes */ *len is the size of plaintext in bytes */
if (!EVP_EncryptUpdate(&m_encryptCtx, ciphertext.GetPointer(), &cipherte xt_len, data.GetPointer(), data.GetSize())) { if (!EVP_EncryptUpdate(m_encryptCtx, ciphertext.GetPointer(), &ciphertex t_len, data.GetPointer(), data.GetSize())) {
PTRACE(1, "H235\tEVP_EncryptUpdate() failed"); PTRACE(1, "H235\tEVP_EncryptUpdate() failed");
} }
// update ciphertext with the final remaining bytes, if any use RTP padd ing // update ciphertext with the final remaining bytes, if any use RTP padd ing
if (!EVP_EncryptFinal_ex(&m_encryptCtx, ciphertext.GetPointer() + cipher text_len, &final_len)) { if (!EVP_EncryptFinal_ex(m_encryptCtx, ciphertext.GetPointer() + ciphert ext_len, &final_len)) {
PTRACE(1, "H235\tEVP_EncryptFinal_ex() failed"); PTRACE(1, "H235\tEVP_EncryptFinal_ex() failed");
} }
} }
ciphertext.SetSize(ciphertext_len + final_len); ciphertext.SetSize(ciphertext_len + final_len);
m_operationCnt++; m_operationCnt++;
return ciphertext; return ciphertext;
} }
PINDEX H235CryptoEngine::EncryptInPlace(const BYTE * inData, PINDEX inLength, BY TE * outData, unsigned char * ivSequence, bool & rtpPadding) PINDEX H235CryptoEngine::EncryptInPlace(const BYTE * inData, PINDEX inLength, BY TE * outData, unsigned char * ivSequence, bool & rtpPadding)
skipping to change at line 471 skipping to change at line 620
PTRACE(1, "H235\tERROR: Encryption not initialised!!"); PTRACE(1, "H235\tERROR: Encryption not initialised!!");
memset(outData,0,inLength); memset(outData,0,inLength);
return inLength; return inLength;
} }
// max ciphertext len for a n bytes of plaintext is n + BLOCK_SIZE -1 bytes // max ciphertext len for a n bytes of plaintext is n + BLOCK_SIZE -1 bytes
int outSize = 0; int outSize = 0;
int inSize = inLength + m_enc_blockSize; int inSize = inLength + m_enc_blockSize;
SetIV(m_iv, ivSequence, m_enc_ivLength); SetIV(m_iv, ivSequence, m_enc_ivLength);
EVP_EncryptInit_ex(&m_encryptCtx, NULL, NULL, NULL, m_iv); EVP_EncryptInit_ex(m_encryptCtx, NULL, NULL, NULL, m_iv);
m_encryptHelper.Reset();
rtpPadding = (inLength % m_enc_blockSize > 0); rtpPadding = (inLength % m_enc_blockSize > 0);
EVP_CIPHER_CTX_set_padding(&m_encryptCtx, rtpPadding ? 1 : 0); EVP_CIPHER_CTX_set_padding(m_encryptCtx, rtpPadding ? 1 : 0);
if (!rtpPadding && (inLength % m_enc_blockSize > 0)) { if (!rtpPadding && (inLength % m_enc_blockSize > 0)) {
// use cyphertext stealing // use cyphertext stealing
if (!EVP_EncryptUpdate_cts(&m_encryptCtx, outData, &inSize, inData, inLe ngth)) { if (!m_encryptHelper.EncryptUpdateCTS(m_encryptCtx, outData, &inSize, in Data, inLength)) {
PTRACE(1, "H235\tEVP_EncryptUpdate_cts() failed"); PTRACE(1, "H235\tEVP_EncryptUpdate_cts() failed");
} }
#if PTLIB_VER >= 2130 if (!m_encryptHelper.EncryptFinalCTS(m_encryptCtx, outData + inSize, &ou
if (!EVP_EncryptFinal_ctsA(&m_encryptCtx, outData + inSize, &outSize)) { tSize)) {
#else
if (!EVP_EncryptFinal_cts(&m_encryptCtx, outData + inSize, &outSize)) {
#endif
PTRACE(1, "H235\tEVP_EncryptFinal_cts() failed"); PTRACE(1, "H235\tEVP_EncryptFinal_cts() failed");
} }
} else { } else {
/* update ciphertext, ciphertext_len is filled with the length of cipher text generated, /* update ciphertext, ciphertext_len is filled with the length of cipher text generated,
*len is the size of plaintext in bytes */ *len is the size of plaintext in bytes */
if (!EVP_EncryptUpdate(&m_encryptCtx, outData, &inSize, inData, inLength )) { if (!EVP_EncryptUpdate(m_encryptCtx, outData, &inSize, inData, inLength) ) {
PTRACE(1, "H235\tEVP_EncryptUpdate() failed"); PTRACE(1, "H235\tEVP_EncryptUpdate() failed");
} }
// update ciphertext with the final remaining bytes, if any use RTP padd ing // update ciphertext with the final remaining bytes, if any use RTP padd ing
if (!EVP_EncryptFinal_ex(&m_encryptCtx, outData + inSize, &outSize)) { if (!EVP_EncryptFinal_ex(m_encryptCtx, outData + inSize, &outSize)) {
PTRACE(1, "H235\tEVP_EncryptFinal_ex() failed"); PTRACE(1, "H235\tEVP_EncryptFinal_ex() failed");
} }
} }
return inSize + outSize; return inSize + outSize;
} }
PBYTEArray H235CryptoEngine::Decrypt(const PBYTEArray & _data, unsigned char * i vSequence, bool & rtpPadding) PBYTEArray H235CryptoEngine::Decrypt(const PBYTEArray & _data, unsigned char * i vSequence, bool & rtpPadding)
{ {
if (!m_initialised) if (!m_initialised)
return PBYTEArray(); return PBYTEArray();
PBYTEArray & data = *(PRemoveConst(PBYTEArray, &_data)); PBYTEArray & data = *(PRemoveConst(PBYTEArray, &_data));
unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH];
/* plaintext will always be equal to or lesser than length of ciphertext*/ /* plaintext will always be equal to or lesser than length of ciphertext*/
int plaintext_len = data.GetSize(); int plaintext_len = data.GetSize();
int final_len = 0; int final_len = 0;
PBYTEArray plaintext(plaintext_len); PBYTEArray plaintext(plaintext_len);
SetIV(iv, ivSequence, EVP_CIPHER_CTX_iv_length(&m_decryptCtx)); SetIV(iv, ivSequence, m_dec_ivLength);
EVP_DecryptInit_ex(&m_decryptCtx, NULL, NULL, NULL, iv); EVP_DecryptInit_ex(m_decryptCtx, NULL, NULL, NULL, iv);
m_decryptHelper.Reset();
EVP_CIPHER_CTX_set_padding(&m_decryptCtx, rtpPadding ? 1 : 0); EVP_CIPHER_CTX_set_padding(m_decryptCtx, rtpPadding ? 1 : 0);
if (!rtpPadding && data.GetSize() % EVP_CIPHER_CTX_block_size(&m_decryptCtx) > 0) { if (!rtpPadding && data.GetSize() % m_dec_blockSize > 0) {
// use cyphertext stealing // use cyphertext stealing
if (!EVP_DecryptUpdate_cts(&m_decryptCtx, plaintext.GetPointer(), &plain if (!m_decryptHelper.DecryptUpdateCTS(m_decryptCtx, plaintext.GetPointer
text_len, data.GetPointer(), data.GetSize())) { (), &plaintext_len, data.GetPointer(), data.GetSize())) {
PTRACE(1, "H235\tEVP_DecryptUpdate_cts() failed"); PTRACE(1, "H235\tDecryptUpdateCTS() failed");
} }
if(!EVP_DecryptFinal_cts(&m_decryptCtx, plaintext.GetPointer() + plainte if(!m_decryptHelper.DecryptFinalCTS(m_decryptCtx, plaintext.GetPointer()
xt_len, &final_len)) { + plaintext_len, &final_len)) {
PTRACE(1, "H235\tEVP_DecryptFinal_cts() failed"); PTRACE(1, "H235\tDecryptFinalCTS() failed");
} }
} else { } else {
if (!EVP_DecryptUpdate(&m_decryptCtx, plaintext.GetPointer(), &plaintext if (!m_decryptHelper.DecryptUpdate(m_decryptCtx, plaintext.GetPointer(),
_len, data.GetPointer(), data.GetSize())) { &plaintext_len, data.GetPointer(), data.GetSize())) {
PTRACE(1, "H235\tEVP_DecryptUpdate() failed"); PTRACE(1, "H235\tDecryptUpdate() failed");
} }
if (!EVP_DecryptFinal_relaxed(&m_decryptCtx, plaintext.GetPointer() + pl if (!m_decryptHelper.DecryptFinalRelaxed(m_decryptCtx, plaintext.GetPoin
aintext_len, &final_len)) { ter() + plaintext_len, &final_len)) {
PTRACE(1, "H235\tEVP_DecryptFinal_ex() failed - incorrect padding ?" PTRACE(1, "H235\tDecryptFinalRelaxed() failed - incorrect padding ?"
); );
} }
} }
rtpPadding = false; // we return the real length of the decrypted dat a without padding rtpPadding = false; // we return the real length of the decrypted dat a without padding
plaintext.SetSize(plaintext_len + final_len); plaintext.SetSize(plaintext_len + final_len);
m_operationCnt++; m_operationCnt++;
return plaintext; return plaintext;
} }
PINDEX H235CryptoEngine::DecryptInPlace(const BYTE * inData, PINDEX inLength, BY TE * outData, unsigned char * ivSequence, bool & rtpPadding) PINDEX H235CryptoEngine::DecryptInPlace(const BYTE * inData, PINDEX inLength, BY TE * outData, unsigned char * ivSequence, bool & rtpPadding)
{ {
/* plaintext will always be equal to or lesser than length of ciphertext*/ /* plaintext will always be equal to or lesser than length of ciphertext*/
int outSize = 0; int outSize = 0;
int inSize = inLength; int inSize = inLength;
SetIV(m_iv, ivSequence, m_dec_ivLength); SetIV(m_iv, ivSequence, m_dec_ivLength);
EVP_DecryptInit_ex(&m_decryptCtx, NULL, NULL, NULL, m_iv); EVP_DecryptInit_ex(m_decryptCtx, NULL, NULL, NULL, m_iv);
m_decryptHelper.Reset();
EVP_CIPHER_CTX_set_padding(&m_decryptCtx, rtpPadding ? 1 : 0); EVP_CIPHER_CTX_set_padding(m_decryptCtx, rtpPadding ? 1 : 0);
if (!rtpPadding && inLength % m_dec_blockSize > 0) { if (!rtpPadding && inLength % m_dec_blockSize > 0) {
// use cyphertext stealing // use cyphertext stealing
if (!EVP_DecryptUpdate_cts(&m_decryptCtx, outData, &inSize, inData, inLe if (!m_decryptHelper.DecryptUpdateCTS(m_decryptCtx, outData, &inSize, in
ngth)) { Data, inLength)) {
PTRACE(1, "H235\tEVP_DecryptUpdate_cts() failed"); PTRACE(1, "H235\tDecryptUpdateCTS() failed");
return 0; // no usable payload return 0; // no usable payload
} }
if(!EVP_DecryptFinal_cts(&m_decryptCtx, outData + inSize, &outSize)) { if(!m_decryptHelper.DecryptFinalCTS(m_decryptCtx, outData + inSize, &out
PTRACE(1, "H235\tEVP_DecryptFinal_cts() failed"); Size)) {
PTRACE(1, "H235\tDecryptFinalCTS() failed");
return 0; // no usable payload return 0; // no usable payload
} }
} else { } else {
if (!EVP_DecryptUpdate(&m_decryptCtx, outData, &inSize, inData, inLength if (!m_decryptHelper.DecryptUpdate(m_decryptCtx, outData, &inSize, inDat
)) { a, inLength)) {
PTRACE(1, "H235\tEVP_DecryptUpdate() failed"); PTRACE(1, "H235\tDecryptUpdate() failed");
return 0; // no usable payload return 0; // no usable payload
} }
if (!EVP_DecryptFinal_relaxed(&m_decryptCtx, outData + inSize, &outSize) if (!m_decryptHelper.DecryptFinalRelaxed(m_decryptCtx, outData + inSize,
) { &outSize)) {
PTRACE(1, "H235\tEVP_DecryptFinal_ex() failed - incorrect padding ?" PTRACE(1, "H235\tDecryptFinalRelaxed() failed - incorrect padding ?"
); );
return 0; // no usable payload return 0; // no usable payload
} }
} }
rtpPadding = false; // we return the real length of the decrypted dat a without padding rtpPadding = false; // we return the real length of the decrypted dat a without padding
return inSize + outSize; return inSize + outSize;
} }
PBYTEArray H235CryptoEngine::GenerateRandomKey() PBYTEArray H235CryptoEngine::GenerateRandomKey()
{ {
PBYTEArray result = GenerateRandomKey(m_algorithmOID); PBYTEArray result = GenerateRandomKey(m_algorithmOID);
 End of changes. 97 change blocks. 
170 lines changed or deleted 323 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)