From bafc1df7c5c15dbdd2e0c0112936a74d97d9f327 Mon Sep 17 00:00:00 2001 From: arif-pragmasys Date: Sat, 17 Oct 2015 11:09:01 -0500 Subject: [PATCH] CTR and CBC mode CNG ciphers replacing OpenSSL ciphers --- .gitignore | 3 +- Makefile.in | 4 +- cipher.c | 68 ++++- cipher.h | 8 +- config.h | 211 +++++++-------- config.h.tail | 1 + contrib/win32/win32compat/Makefile.in | 17 +- contrib/win32/win32compat/cng_cipher.c | 298 +++++++++++++++++++++ contrib/win32/win32compat/cng_cipher.h | 64 +++++ contrib/win32/win32compat/libwin32compat.q | 1 + contrib/win32/win32compat/makefile.save | 50 ++++ openbsd-compat/regress/Makefile | 6 +- 12 files changed, 612 insertions(+), 119 deletions(-) create mode 100644 contrib/win32/win32compat/cng_cipher.c create mode 100644 contrib/win32/win32compat/cng_cipher.h create mode 100644 contrib/win32/win32compat/libwin32compat.q create mode 100644 contrib/win32/win32compat/makefile.save diff --git a/.gitignore b/.gitignore index 369bb8e..904aa1f 100644 --- a/.gitignore +++ b/.gitignore @@ -262,4 +262,5 @@ regress/rsa_ssh2_crnl.prv regress/t7.out.pub regress/t6.out2 config.h -configure \ No newline at end of file +configure +config.h \ No newline at end of file diff --git a/Makefile.in b/Makefile.in index 34f8341..c52a1c8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -44,7 +44,7 @@ CC=@CC@ LD=@LD@ CFLAGS=@CFLAGS@ CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -LIBS=@LIBS@ +LIBS=@LIBS@ -lbcrypt K5LIBS=@K5LIBS@ GSSLIBS=@GSSLIBS@ SSHLIBS=@SSHLIBS@ @@ -58,7 +58,7 @@ PERL=@PERL@ SED=@SED@ ENT=@ENT@ XAUTH_PATH=@XAUTH_PATH@ -LDFLAGS=-L. -Lopenbsd-compat/ -Lcontrib/win32/win32compat @LDFLAGS@ +LDFLAGS=-L. -Lopenbsd-compat/ -Lcontrib/win32/win32compat @LDFLAGS@ -L/cygdrive/C/cygwin-32/lib/w32api EXEEXT=@EXEEXT@ MANFMT=@MANFMT@ diff --git a/cipher.c b/cipher.c index 02dae6f..09a0580 100644 --- a/cipher.c +++ b/cipher.c @@ -34,7 +34,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - + #include "includes.h" #include @@ -43,6 +43,7 @@ #include #include + #include "cipher.h" #include "misc.h" #include "sshbuf.h" @@ -51,6 +52,12 @@ #include "openbsd-compat/openssl-compat.h" + + +#ifdef USE_MSCNG +#undef WITH_OPENSSL +#endif + #ifdef WITH_SSH1 extern const EVP_CIPHER *evp_ssh1_bf(void); extern const EVP_CIPHER *evp_ssh1_3des(void); @@ -108,9 +115,19 @@ static const struct sshcipher ciphers[] = { SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, # endif /* OPENSSL_HAVE_EVPGCM */ #else /* WITH_OPENSSL */ + +#ifdef USE_MSCNG + { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, _CNG_CIPHER_AES | _CNG_MODE_CTR, NULL }, + { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, _CNG_CIPHER_AES | _CNG_MODE_CTR, NULL }, + { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, _CNG_CIPHER_AES | _CNG_MODE_CTR, NULL }, + { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, _CNG_CIPHER_AES | _CNG_MODE_CBC, NULL }, + { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, _CNG_CIPHER_AES | _CNG_MODE_CBC, NULL }, + { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, _CNG_CIPHER_AES | _CNG_MODE_CBC, NULL }, +#else { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL }, { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL }, { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, CFLAG_AESCTR, NULL }, +#endif { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL }, #endif /* WITH_OPENSSL */ { "chacha20-poly1305@openssh.com", @@ -293,6 +310,8 @@ cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher, const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, int do_encrypt) { + + #ifdef WITH_OPENSSL int ret = SSH_ERR_INTERNAL_ERROR; const EVP_CIPHER *type; @@ -316,11 +335,25 @@ cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher, return chachapoly_init(&cc->cp_ctx, key, keylen); } #ifndef WITH_OPENSSL + +#ifdef USE_MSCNG + + /* cng shares cipher flag with NONE. Make sure the NONE cipher isn't requested */ + if ((cc->cipher->flags & CFLAG_NONE) == 0) + { + + if (cng_cipher_init(&cc->cng_ctx,key,keylen,iv, ivlen,cc->cipher->flags)) + return SSH_ERR_LIBCRYPTO_ERROR; + + return 0; + } +#else if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen); aesctr_ivsetup(&cc->ac_ctx, iv); return 0; } +#endif if ((cc->cipher->flags & CFLAG_NONE) != 0) return 0; return SSH_ERR_INVALID_ARGUMENT; @@ -373,6 +406,7 @@ cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher, return 0; } + /* * cipher_crypt() operates as following: * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. @@ -387,18 +421,44 @@ int cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen) { +#ifdef USE_MSCNG + int ret = 0; +#endif + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, authlen, cc->encrypt); } #ifndef WITH_OPENSSL - if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { + +#ifdef USE_MSCNG + + /* cng shares cipher flag with NONE. Make sure the NONE cipher isn't requested */ + if ((cc->cipher->flags & CFLAG_NONE) == 0) + { + if (aadlen) + memcpy(dest, src, aadlen); + if (cc->encrypt) + ret = cng_cipher_encrypt(&cc->cng_ctx,dest+aadlen, len, src+aadlen,len); + else + ret = cng_cipher_decrypt(&cc->cng_ctx,dest+aadlen, len, src+aadlen, len); + + if (ret != len){ + return SSH_ERR_LIBCRYPTO_ERROR; + } + return 0; + } +#else + if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { if (aadlen) memcpy(dest, src, aadlen); aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen, dest + aadlen, len); return 0; } +#endif + + if ((cc->cipher->flags & CFLAG_NONE) != 0) { memcpy(dest, src, aadlen + len); return 0; @@ -472,6 +532,10 @@ cipher_cleanup(struct sshcipher_ctx *cc) else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) return SSH_ERR_LIBCRYPTO_ERROR; #endif +#ifdef USE_MSCNG + else + cng_cipher_cleanup(&cc->cng_ctx); +#endif return 0; } diff --git a/cipher.h b/cipher.h index 06d4be4..6b49b4d 100644 --- a/cipher.h +++ b/cipher.h @@ -41,7 +41,9 @@ #include #include "cipher-chachapoly.h" #include "cipher-aesctr.h" - +#ifdef USE_MSCNG +#include "contrib/win32/win32compat/cng_cipher.h" +#endif /* * Cipher types for SSH-1. New types can be added, but old types should not * be removed for compatibility. The maximum allowed value is 31. @@ -70,6 +72,10 @@ struct sshcipher_ctx { struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ struct aesctr_ctx ac_ctx; /* XXX union with evp? */ const struct sshcipher *cipher; + #ifdef USE_MSCNG + struct ssh_cng_cipher_ctx cng_ctx; + #endif + }; u_int cipher_mask_ssh1(int); diff --git a/config.h b/config.h index 06ac8a3..6263001 100644 --- a/config.h +++ b/config.h @@ -83,7 +83,7 @@ /* #undef BSD_AUTH */ /* Define if you want to specify the path to your lastlog file */ -/* #undef CONF_LASTLOG_FILE */ +#define CONF_LASTLOG_FILE "/var/log/lastlog" /* Define if you want to specify the path to your utmp file */ #define CONF_UTMP_FILE "/var/run/utmp" @@ -1540,107 +1540,108 @@ /* type to use in place of socklen_t if not defined */ /* #undef socklen_t */ -#define WIN32_LEAN_AND_MEAN 1 -#define _CRT_SECURE_NO_DEPRECATE 1 -#define _CRT_NONSTDC_NO_DEPRECATE 1 -#define WIN32_FIXME 1 -#undef USE_NTCREATETOKEN - -/* Define if you must implement a startup_needs function for your platform */ -#define HAVE_STARTUP_NEEDS 1 - -/* Define if your platform uses Winsock instead of BSD sockets (yeah, there are a lot of platforms like this :) */ -#define HAVE_WINSOCK 1 - -#define snprintf _snprintf - -#define BROKEN_READV_COMPARISON - -/* Override detection of some headers and functions on MinGW */ -#undef BROKEN_SNPRINTF -#define GETPGRP_VOID 1 -#undef HAVE_CRYPT_H -#define HAVE_DAEMON 1 -#undef HAVE_ENDIAN_H -#undef HAVE_FCNTL_H -#define HAVE_FREEADDRINFO 1 -#define HAVE_GAI_STRERROR 1 -#define HAVE_GETADDRINFO 1 -#define HAVE_GETGROUPLIST 1 -#define HAVE_GETNAMEINFO 1 -#undef HAVE_ID_IN_UTMPX -#define HAVE_INET_ATON 1 -#define HAVE_INET_NTOA 1 -#define HAVE_INNETGR 1 -#undef HAVE_LIBCRYPT -#define HAVE_MKDTEMP 1 -#define HAVE_NANOSLEEP 1 -#undef HAVE_PATHS_H -#undef HAVE_POLL_H -#undef HAVE_PROC_PID -#undef HAVE_PTY_H -#define HAVE_NANOSLEEP 1 -#define HAVE_READPASSPHRASE 1 -#define HAVE_REALPATH 1 -#undef HAVE_SIG_ATOMIC_T -#define HAVE_SIZE_T 1 -#undef HAVE_STRERROR -#define HAVE_STRMODE 1 -#undef __USE_W32_SOCKETS - -#ifdef __MINGW32__ /* FIXME: Use autoconf to set this correctly */ -/* Define to 1 if you have the `strcasecmp' function. */ -#define HAVE_STRCASECMP 1 - -/* Define to 1 if you have the `strncasecmp' function. */ -#define HAVE_STRNCASECMP 1 -#endif - -#define HAVE_STRUCT_IN6_ADDR 1 -#define HAVE_STRUCT_SOCKADDR_IN6 1 -#define HAVE_STRUCT_TIMEVAL 1 -#undef HAVE_SYS_CDEFS_H -#undef HAVE_SYS_SYSMACROS_H -#undef HAVE_SYS_MMAN_H -#undef HAVE_SYS_UN_H - -#define HAVE_TCGETPGRP 1 - -#undef HAVE_TIME - -#define HAVE_TRUNCATE 1 - -#define HAVE_VIS_H 1 - -#define MISSING_FD_MASK 1 -#define MISSING_HOWMANY 1 -#define MISSING_NFDBITS 1 - -#undef SSH_PRIVSEP_USER - -#define HAVE_OPENPTY 1 - -/* Fixes for loginrec.c */ -#undef CONF_UTMP_FILE -#undef CONF_WTMPX_FILE -#undef CONF_WTMP_FILE -#undef CONF_UTMPX_FILE -#undef CONF_LASTLOG_FILE - -#define BROKEN_SYS_TERMIO_H - -#define strerror strerror_win32 - -#define strerror strerror_win32 - -// PRAGMA SYS PORT -#define WITH_OPENSSL 1 -#define HAVE_KRB5_GET_ERROR_MESSAGE 1 -#define HAVE_KRB5_FREE_ERROR_MESSAGE 1 -#define HAVE_DECL_NFDBITS 0 -#define HAVE_DECL_HOWMANY 0 - -#define WIN32_ZLIB_NO 1 - -//#define HAVE_ARC4RANDOM_UNIFORM 1 - +#define WIN32_LEAN_AND_MEAN 1 +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#define WIN32_FIXME 1 +#undef USE_NTCREATETOKEN + +/* Define if you must implement a startup_needs function for your platform */ +#define HAVE_STARTUP_NEEDS 1 + +/* Define if your platform uses Winsock instead of BSD sockets (yeah, there are a lot of platforms like this :) */ +#define HAVE_WINSOCK 1 + +#define snprintf _snprintf + +#define BROKEN_READV_COMPARISON + +/* Override detection of some headers and functions on MinGW */ +#undef BROKEN_SNPRINTF +#define GETPGRP_VOID 1 +#undef HAVE_CRYPT_H +#define HAVE_DAEMON 1 +#undef HAVE_ENDIAN_H +#undef HAVE_FCNTL_H +#define HAVE_FREEADDRINFO 1 +#define HAVE_GAI_STRERROR 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETGROUPLIST 1 +#define HAVE_GETNAMEINFO 1 +#undef HAVE_ID_IN_UTMPX +#define HAVE_INET_ATON 1 +#define HAVE_INET_NTOA 1 +#define HAVE_INNETGR 1 +#undef HAVE_LIBCRYPT +#define HAVE_MKDTEMP 1 +#define HAVE_NANOSLEEP 1 +#undef HAVE_PATHS_H +#undef HAVE_POLL_H +#undef HAVE_PROC_PID +#undef HAVE_PTY_H +#define HAVE_NANOSLEEP 1 +#define HAVE_READPASSPHRASE 1 +#define HAVE_REALPATH 1 +#undef HAVE_SIG_ATOMIC_T +#define HAVE_SIZE_T 1 +#undef HAVE_STRERROR +#define HAVE_STRMODE 1 +#undef __USE_W32_SOCKETS + +#ifdef __MINGW32__ /* FIXME: Use autoconf to set this correctly */ +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 +#endif + +#define HAVE_STRUCT_IN6_ADDR 1 +#define HAVE_STRUCT_SOCKADDR_IN6 1 +#define HAVE_STRUCT_TIMEVAL 1 +#undef HAVE_SYS_CDEFS_H +#undef HAVE_SYS_SYSMACROS_H +#undef HAVE_SYS_MMAN_H +#undef HAVE_SYS_UN_H + +#define HAVE_TCGETPGRP 1 + +#undef HAVE_TIME + +#define HAVE_TRUNCATE 1 + +#define HAVE_VIS_H 1 + +#define MISSING_FD_MASK 1 +#define MISSING_HOWMANY 1 +#define MISSING_NFDBITS 1 + +#undef SSH_PRIVSEP_USER + +#define HAVE_OPENPTY 1 + +/* Fixes for loginrec.c */ +#undef CONF_UTMP_FILE +#undef CONF_WTMPX_FILE +#undef CONF_WTMP_FILE +#undef CONF_UTMPX_FILE +#undef CONF_LASTLOG_FILE + +#define BROKEN_SYS_TERMIO_H + +#define strerror strerror_win32 + +#define strerror strerror_win32 + +// PRAGMA SYS PORT +#define WITH_OPENSSL 1 +#define HAVE_KRB5_GET_ERROR_MESSAGE 1 +#define HAVE_KRB5_FREE_ERROR_MESSAGE 1 +#define HAVE_DECL_NFDBITS 0 +#define HAVE_DECL_HOWMANY 0 + +#define WIN32_ZLIB_NO 1 +#define USE_MSCNG 1 + +//#define HAVE_ARC4RANDOM_UNIFORM 1 + diff --git a/config.h.tail b/config.h.tail index 8b6d40c..5336f54 100644 --- a/config.h.tail +++ b/config.h.tail @@ -99,6 +99,7 @@ #define HAVE_DECL_HOWMANY 0 #define WIN32_ZLIB_NO 1 +#define USE_MSCNG 1 //#define HAVE_ARC4RANDOM_UNIFORM 1 diff --git a/contrib/win32/win32compat/Makefile.in b/contrib/win32/win32compat/Makefile.in index 3be0243..2661cb2 100644 --- a/contrib/win32/win32compat/Makefile.in +++ b/contrib/win32/win32compat/Makefile.in @@ -8,25 +8,32 @@ top_srcdir=@top_srcdir@ VPATH=@srcdir@ CC=@CC@ LD=@LD@ -CFLAGS=@CFLAGS@ -CPPFLAGS=-I. -I../../.. -I$(srcdir) -I$(top_srcdir) -I$(srcdir)/includes @CPPFLAGS@ @DEFS@ -LIBS=@LIBS@ +BCRYPTFLAGS=-I/usr/include/w32api +CFLAGS=@CFLAGS@ +CPPFLAGS=-I. -I../../.. -I$(srcdir) -I$(top_srcdir) -I$(srcdir)/includes @CPPFLAGS@ @DEFS@ -DUSE_MSCNG +LIBS=@LIBS@ -lbcrypt AR=@AR@ RANLIB=@RANLIB@ INSTALL=@INSTALL@ -LDFLAGS=-L. @LDFLAGS@ +LDFLAGS=-L. @LDFLAGS@ -L/lib/win32api WIN32COMPATFILES = daemon.o gettimeofday.o homedirhelp.o pwd.o sfds.o \ socket.o startupneeds.o strcasecmp.o syslog.o lsalogon.o lsastring.o \ - stringhelp.o deskright.o win32auth.o kerberos.o ansiprsr.o console.o tnnet.o + stringhelp.o deskright.o win32auth.o kerberos.o cng_cipher.o ansiprsr.o console.o tnnet.o WIN32COMPATLIB=@LIBWIN32COMPAT@ +CNGFILES=cng_cipher.o + + .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< all: $(WIN32COMPATLIB) +$(CNGFILES): %.o: %.c + $(CC) $(CFLAGS) $(BCRYPTFLAGS) $(CPPFLAGS) -c $< + install: clean: diff --git a/contrib/win32/win32compat/cng_cipher.c b/contrib/win32/win32compat/cng_cipher.c new file mode 100644 index 0000000..d95db8c --- /dev/null +++ b/contrib/win32/win32compat/cng_cipher.c @@ -0,0 +1,298 @@ +/* cng_cipher.c +* Author: Pragma Systems, Inc. +* Contribution by Pragma Systems, Inc. for Microsoft openssh win32 port +* Copyright (c) 2011, 2015 Pragma Systems, Inc. +* All rights reserved +* +* Common library for Windows Console Screen IO. +* Contains Windows console related definition so that emulation code can draw +* on Windows console screen surface. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice. +* 2. Binaries produced provide no direct or implied warranties or any +* guarantee of performance or suitability. +*/ + +#include +#include + +#include "cng_cipher.h" + +#ifdef USE_MSCNG + + +#define AES_BLOCK_SIZE 16 + + +/* +* increment the aes counter (iv) +*/ +static void aesctr_inc(unsigned char *ctr, unsigned int len) +{ + size_t i; + +#ifndef CONSTANT_TIME_INCREMENT + for (i = len - 1; i >= 0; i--) + if (++ctr[i]) /* continue on overflow */ + return; +#else + u8 x, add = 1; + + for (i = len - 1; i >= 0; i--) { + ctr[i] += add; + /* constant time for: x = ctr[i] ? 1 : 0 */ + x = ctr[i]; + x = (x | (x >> 4)) & 0xf; + x = (x | (x >> 2)) & 0x3; + x = (x | (x >> 1)) & 0x1; + add *= (x ^ 1); + } +#endif +} + + +/* +* Routine to encrypt a counter for ctr encryption. This requries +* us to use an IV that is reset for each call to avoid cng attempting +* to chain encryptions. +*/ +DWORD cng_counter_encrypt(const unsigned char *in, unsigned char *out, BCRYPT_KEY_HANDLE key, unsigned int blocklen) +{ + HRESULT status = S_OK; + DWORD cbResult = 0; + + unsigned char iv[AES_BLOCK_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + status = BCryptEncrypt( + key, + (PUCHAR)in, + blocklen, + NULL, + iv, + blocklen, + out, + blocklen, + &cbResult, + 0); + + return cbResult; +} + +/* +* Encrypt/Decrypt data using a CTR mode. +* In this mode, we can't call CNG encryption/decription directly. The mode requires +* the use of the iv as a counter that is incremented and encrypted. The +* encrypted counter is then XORd with the data to produce the cipher text. +*/ +int cng_aesctr_encrypt_bytes(PSSH_CNG_CIPHER_CTX x, const unsigned char *m, unsigned char *c, unsigned int bytes) +{ + int ret = 0; + unsigned int n = 0; + unsigned char buf[AES_BLOCK_SIZE]; + + while ((bytes--) > 0) { + if (n == 0) { + if (!cng_counter_encrypt(x->pbIV, buf, x->hKey, AES_BLOCK_SIZE)) + { + ret = -1; + break; + } + aesctr_inc(x->pbIV, AES_BLOCK_SIZE); + } + *(c++) = *(m++) ^ buf[n]; + n = (n + 1) % AES_BLOCK_SIZE; + } + return ret; +} + + +/* +* Encrypt data using a provided cipher context +*/ +unsigned int cng_cipher_encrypt(PSSH_CNG_CIPHER_CTX x, unsigned char *dest, unsigned int dest_len, const unsigned char *src, unsigned int len) +{ + DWORD cbResult = 0; + HRESULT status = S_OK; + + if (x->flags & _CNG_MODE_CTR) + { + if (-1 == cng_aesctr_encrypt_bytes(x, src, dest, len)) + { + status = GetLastError(); + } + cbResult = len; + } + else + { + + status = BCryptEncrypt( + x->hKey, + (PUCHAR)src, + len, + NULL, + x->pbIV, + x->cbBlockSize, + dest, + dest_len, + &cbResult, + 0); + if (S_OK != status) + { + cbResult = 0; + SetLastError(status); + } + } + return cbResult; +} + +/* +* Decrypt encrypted data using a provided cipher context +*/ +unsigned int cng_cipher_decrypt(PSSH_CNG_CIPHER_CTX x, unsigned char *dest, unsigned int dest_len, const unsigned char *src, unsigned int len) +{ + DWORD cbResult = 0; + HRESULT status = S_OK; + + if (x->flags & _CNG_MODE_CTR) + { + // ctr mode is just an XOR so encrypt=decrypt + if (-1 == cng_aesctr_encrypt_bytes(x, src, dest, len)) + { + status = GetLastError(); + } + cbResult = len; + } + else + { + + status = BCryptDecrypt( + x->hKey, + (PUCHAR)src, + len, + NULL, + x->pbIV, + x->cbBlockSize, + dest, + dest_len, + &cbResult, + 0); + if (S_OK != status) + { + cbResult = 0; + SetLastError(status); + } + } + return cbResult; +} + + +/* +* Initialize cipher context +*/ +unsigned int cng_cipher_init(PSSH_CNG_CIPHER_CTX x, const unsigned char *key, unsigned int keylen, const unsigned char *iv, size_t ivlen, unsigned int flags) +{ + HRESULT status = S_OK; + BCRYPT_ALG_HANDLE hAlg = NULL; + DWORD cbData = 0; + LPCWSTR pAlg = NULL; + DWORD cbBlockLen = 0; + + if ((0 == (flags & _CNG_CIPHER_AES)) || (0 == (flags & (_CNG_MODE_CBC | _CNG_MODE_CTR)))) + return STATUS_INVALID_PARAMETER; + + + + // wipe out old context + memset(x, 0, sizeof(SSH_CNG_CIPHER_CTX)); + + + // initialize simple context fields + x->flags = flags; + + // only one cipher supported right now + if (flags & _CNG_CIPHER_AES) + pAlg = BCRYPT_AES_ALGORITHM; + + + // Generate BCrypt Key and set mode if applicable + if (NT_SUCCESS(status = BCryptOpenAlgorithmProvider( + &hAlg, + pAlg, + NULL, + 0))) + { + + if (NT_SUCCESS(status = BCryptGetProperty( + hAlg, + BCRYPT_BLOCK_LENGTH, + (PBYTE)&cbBlockLen, + sizeof(DWORD), + &cbData, + 0))) + { + x->cbBlockSize = cbBlockLen; + if (cbBlockLen != ivlen) + { + status = STATUS_INVALID_PARAMETER; + } + else + { + x->pbIV = (PBYTE)HeapAlloc(GetProcessHeap(), 0, ivlen); + if (NULL == x->pbIV) + { + status = GetLastError(); + } + else + { + memcpy(x->pbIV, iv, ivlen); + } + } + } + + + if (status == S_OK && flags & _CNG_MODE_CBC) + { + status = BCryptSetProperty( + hAlg, + BCRYPT_CHAINING_MODE, + (PBYTE)BCRYPT_CHAIN_MODE_CBC, + sizeof(BCRYPT_CHAIN_MODE_CBC), + 0); + } + + if (status == S_OK) + { + status = BCryptGenerateSymmetricKey( + hAlg, + &(x->hKey), + NULL, + 0, + (PBYTE)key, + keylen, + 0); + } + BCryptCloseAlgorithmProvider(hAlg, 0); + + // if we got an error along the way, free up the iv + if (status != S_OK && x->pbIV) + { + HeapFree(GetProcessHeap(), 0, x->pbIV); + } + } + return status; +} +/* +* Cleanup cipher context fields +*/ +void cng_cipher_cleanup(PSSH_CNG_CIPHER_CTX x) +{ + if (x->pbIV) + HeapFree(GetProcessHeap(), 0, x->pbIV); + if (x->hKey) + BCryptDestroyKey(x->hKey); +} + +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/cng_cipher.h b/contrib/win32/win32compat/cng_cipher.h new file mode 100644 index 0000000..8b9ca9d --- /dev/null +++ b/contrib/win32/win32compat/cng_cipher.h @@ -0,0 +1,64 @@ +/* cng_cipher.h +* Author: Pragma Systems, Inc. +* Contribution by Pragma Systems, Inc. for Microsoft openssh win32 port +* Copyright (c) 2011, 2015 Pragma Systems, Inc. +* All rights reserved +* +* Common library for Windows Console Screen IO. +* Contains Windows console related definition so that emulation code can draw +* on Windows console screen surface. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice. +* 2. Binaries produced provide no direct or implied warranties or any +* guarantee of performance or suitability. +*/ + + +#ifndef CNG_CIPHER_H +#define CNG_CIPHER_H + +#ifdef USE_MSCNG + +#ifdef __cplusplus +extern "C" { +#endif + +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) + +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) + +/* CIPHER/MODE bits specify cipher and mode in the flags +* field of the context +*/ +#define _CNG_CIPHER_AES 0x00000001 +#define _CNG_MODE_CTR 0x00010000 +#define _CNG_MODE_CBC 0x00020000 + +#define _CNG_CIPHER_MASK 0x0000FFFF +#define _CNG_MODE_MASK 0xFFFF0000 + + typedef struct ssh_cng_cipher_ctx + { + void * hKey; + unsigned char * pbIV; + unsigned int cbBlockSize; + unsigned int flags; + } SSH_CNG_CIPHER_CTX, *PSSH_CNG_CIPHER_CTX; + + + unsigned int cng_cipher_encrypt(PSSH_CNG_CIPHER_CTX x, unsigned char *dest, unsigned int dest_len, const unsigned char *src, unsigned int len); + unsigned int cng_cipher_decrypt(PSSH_CNG_CIPHER_CTX x, unsigned char *dest, unsigned int dest_len, const unsigned char *src, unsigned int len); + unsigned int cng_cipher_init(PSSH_CNG_CIPHER_CTX x, const unsigned char *key, unsigned int keylen, const unsigned char *iv, size_t ivlen, unsigned int flags); + void cng_cipher_cleanup(PSSH_CNG_CIPHER_CTX x); + + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/libwin32compat.q b/contrib/win32/win32compat/libwin32compat.q new file mode 100644 index 0000000..8b277f0 --- /dev/null +++ b/contrib/win32/win32compat/libwin32compat.q @@ -0,0 +1 @@ +! diff --git a/contrib/win32/win32compat/makefile.save b/contrib/win32/win32compat/makefile.save new file mode 100644 index 0000000..8413d7b --- /dev/null +++ b/contrib/win32/win32compat/makefile.save @@ -0,0 +1,50 @@ +# $Id $ + +sysconfdir=${prefix}/etc +piddir=/var/run +srcdir=. +top_srcdir=../../.. + + +CC=i686-pc-mingw32-gcc +LD=i686-pc-mingw32-gcc +CFLAGS=-g -O2 -Wall -Wpointer-arith -Wuninitialized -Wsign-compare -Wformat-security -Wno-pointer-sign -Wno-unused-result -fno-strict-aliasing -fno-builtin-memset -I/cygdrive/c/openssh/Win32-OpenSSH/contrib/win32/win32compat/includes -I/cygdrive/c/openssh/Win32-OpenSSH/openbsd-compat -I/cygdrive/c/openssh/Win32-OpenSSH/contrib/win32/win32compat/includes -I/cygdrive/c/openssh/Win32-OpenSSH/libkrb -I/usr/local +BCRYPTFLAGS=-I/usr/include/w32api +CPPFLAGS=-I. -I../../.. -I$(srcdir) -I$(top_srcdir) -I$(srcdir)/includes -I/cygdrive/c/openssh/Win32-OpenSSH/../openssl-1.0.2d/include -DHAVE_CONFIG_H -DUSE_MSCNG +LIBS=-lcrypto -lz -lws2_32 -lgdi32 -lNetAPI32 -luserenv -lsecur32 -lshlwapi -lbcrypt +AR=/usr/bin/ar +RANLIB=i686-pc-mingw32-ranlib +INSTALL=/usr/bin/install -c +LDFLAGS=-L. -L/cygdrive/c/openssh/Win32-OpenSSH/../openssl-1.0.2d -L/lib/win32api + +WIN32COMPATFILES = daemon.o gettimeofday.o homedirhelp.o pwd.o sfds.o \ + socket.o startupneeds.o strcasecmp.o syslog.o lsalogon.o lsastring.o \ + stringhelp.o deskright.o win32auth.o kerberos.o cng_cipher.o ansiprsr.o console.o tnnet.o + +WIN32COMPATLIB=libwin32compat.a + +CNGFILES=cng_cipher.o + + +.c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + +all: $(WIN32COMPATLIB) + + +$(CNGFILES): %.o: %.c + $(CC) $(CFLAGS) $(BCRYPTFLAGS) $(CPPFLAGS) -c $< + +install: + +clean: + rm -f *.o *.a core + +distclean: clean + rm -f Makefile *~ + +$(WIN32COMPATFILES): ../../../config.h + +$(WIN32COMPATLIB): $(WIN32COMPATFILES) + $(AR) rv $@ $(WIN32COMPATFILES) + $(RANLIB) $@ diff --git a/openbsd-compat/regress/Makefile b/openbsd-compat/regress/Makefile index 541a8d8..0ae9270 100644 --- a/openbsd-compat/regress/Makefile +++ b/openbsd-compat/regress/Makefile @@ -8,12 +8,12 @@ top_srcdir=../.. CC=i686-pc-mingw32-gcc LD=i686-pc-mingw32-gcc -CFLAGS=-g -O2 -Wall -Wpointer-arith -Wuninitialized -Wsign-compare -Wformat-security -Wno-pointer-sign -Wno-unused-result -fno-strict-aliasing -fno-builtin-memset -fstack-protector-all -I/cygdrive/c/openssh/Win32-OpenSSH/contrib/win32/win32compat/includes -I/cygdrive/c/openssh/Win32-OpenSSH/openbsd-compat -I/cygdrive/c/openssh/Win32-OpenSSH/contrib/win32/win32compat/includes -I/cygdrive/c/openssh/Win32-OpenSSH/libkrb -I/usr/local -CPPFLAGS=-I. -I.. -I$(srcdir) -I$(srcdir)/.. -I/cygdrive/c/openssh/openssl-1.0.2d/include -I/cygdrive/c/openssh/zlib-1.2.8 -DHAVE_CONFIG_H +CFLAGS=-g -O2 -Wall -Wpointer-arith -Wuninitialized -Wsign-compare -Wformat-security -Wno-pointer-sign -Wno-unused-result -fno-strict-aliasing -fno-builtin-memset -I/cygdrive/c/openssh/Win32-OpenSSH/contrib/win32/win32compat/includes -I/cygdrive/c/openssh/Win32-OpenSSH/openbsd-compat -I/cygdrive/c/openssh/Win32-OpenSSH/contrib/win32/win32compat/includes -I/cygdrive/c/openssh/Win32-OpenSSH/libkrb -I/usr/local +CPPFLAGS=-I. -I.. -I$(srcdir) -I$(srcdir)/.. -I/cygdrive/c/openssh/Win32-OpenSSH/../openssl-1.0.2d/include -DHAVE_CONFIG_H EXEEXT=.exe LIBCOMPAT=../libopenbsd-compat.a LIBS=-lcrypto -lz -lws2_32 -lgdi32 -lNetAPI32 -luserenv -lsecur32 -lshlwapi -LDFLAGS=-L/cygdrive/c/openssh/openssl-1.0.2d -L/cygdrive/c/openssh/zlib-1.2.8 -fstack-protector-all $(LIBCOMPAT) +LDFLAGS=-L/cygdrive/c/openssh/Win32-OpenSSH/../openssl-1.0.2d $(LIBCOMPAT) TESTPROGS=closefromtest$(EXEEXT) snprintftest$(EXEEXT) strduptest$(EXEEXT) \ strtonumtest$(EXEEXT) opensslvertest$(EXEEXT)