summaryrefslogtreecommitdiff
path: root/libssh2-sys/libssh2-1.5.0/src/wincng.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh2-sys/libssh2-1.5.0/src/wincng.c')
-rw-r--r--libssh2-sys/libssh2-1.5.0/src/wincng.c1827
1 files changed, 1827 insertions, 0 deletions
diff --git a/libssh2-sys/libssh2-1.5.0/src/wincng.c b/libssh2-sys/libssh2-1.5.0/src/wincng.c
new file mode 100644
index 0000000..4a8aa16
--- /dev/null
+++ b/libssh2-sys/libssh2-1.5.0/src/wincng.c
@@ -0,0 +1,1827 @@
+/*
+ * Copyright (C) 2013-2014 Marc Hoersken <info@marc-hoersken.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the copyright holder nor the names
+ * of any other contributors may be used to endorse or
+ * promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 "libssh2_priv.h"
+
+#ifdef LIBSSH2_WINCNG /* compile only if we build with wincng */
+
+/* required for cross-compilation against the w64 mingw-runtime package */
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600)
+#undef _WIN32_WINNT
+#endif
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+#endif
+
+/* specify the required libraries for dependencies using MSVC */
+#ifdef _MSC_VER
+#pragma comment(lib, "bcrypt.lib")
+#ifdef HAVE_LIBCRYPT32
+#pragma comment(lib, "crypt32.lib")
+#endif
+#endif
+
+#include <windows.h>
+#include <bcrypt.h>
+#include <math.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_LIBCRYPT32
+#include <wincrypt.h>
+#endif
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: Missing definitions (for MinGW[-w64])
+ */
+#ifndef BCRYPT_SUCCESS
+#define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
+#endif
+
+#ifndef BCRYPT_RNG_ALGORITHM
+#define BCRYPT_RNG_ALGORITHM L"RNG"
+#endif
+
+#ifndef BCRYPT_MD5_ALGORITHM
+#define BCRYPT_MD5_ALGORITHM L"MD5"
+#endif
+
+#ifndef BCRYPT_SHA1_ALGORITHM
+#define BCRYPT_SHA1_ALGORITHM L"SHA1"
+#endif
+
+#ifndef BCRYPT_RSA_ALGORITHM
+#define BCRYPT_RSA_ALGORITHM L"RSA"
+#endif
+
+#ifndef BCRYPT_DSA_ALGORITHM
+#define BCRYPT_DSA_ALGORITHM L"DSA"
+#endif
+
+#ifndef BCRYPT_AES_ALGORITHM
+#define BCRYPT_AES_ALGORITHM L"AES"
+#endif
+
+#ifndef BCRYPT_RC4_ALGORITHM
+#define BCRYPT_RC4_ALGORITHM L"RC4"
+#endif
+
+#ifndef BCRYPT_3DES_ALGORITHM
+#define BCRYPT_3DES_ALGORITHM L"3DES"
+#endif
+
+#ifndef BCRYPT_ALG_HANDLE_HMAC_FLAG
+#define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008
+#endif
+
+#ifndef BCRYPT_DSA_PUBLIC_BLOB
+#define BCRYPT_DSA_PUBLIC_BLOB L"DSAPUBLICBLOB"
+#endif
+
+#ifndef BCRYPT_DSA_PUBLIC_MAGIC
+#define BCRYPT_DSA_PUBLIC_MAGIC 0x42505344 /* DSPB */
+#endif
+
+#ifndef BCRYPT_DSA_PRIVATE_BLOB
+#define BCRYPT_DSA_PRIVATE_BLOB L"DSAPRIVATEBLOB"
+#endif
+
+#ifndef BCRYPT_DSA_PRIVATE_MAGIC
+#define BCRYPT_DSA_PRIVATE_MAGIC 0x56505344 /* DSPV */
+#endif
+
+#ifndef BCRYPT_RSAPUBLIC_BLOB
+#define BCRYPT_RSAPUBLIC_BLOB L"RSAPUBLICBLOB"
+#endif
+
+#ifndef BCRYPT_RSAPUBLIC_MAGIC
+#define BCRYPT_RSAPUBLIC_MAGIC 0x31415352 /* RSA1 */
+#endif
+
+#ifndef BCRYPT_RSAFULLPRIVATE_BLOB
+#define BCRYPT_RSAFULLPRIVATE_BLOB L"RSAFULLPRIVATEBLOB"
+#endif
+
+#ifndef BCRYPT_RSAFULLPRIVATE_MAGIC
+#define BCRYPT_RSAFULLPRIVATE_MAGIC 0x33415352 /* RSA3 */
+#endif
+
+#ifndef BCRYPT_KEY_DATA_BLOB
+#define BCRYPT_KEY_DATA_BLOB L"KeyDataBlob"
+#endif
+
+#ifndef BCRYPT_MESSAGE_BLOCK_LENGTH
+#define BCRYPT_MESSAGE_BLOCK_LENGTH L"MessageBlockLength"
+#endif
+
+#ifndef BCRYPT_NO_KEY_VALIDATION
+#define BCRYPT_NO_KEY_VALIDATION 0x00000008
+#endif
+
+#ifndef BCRYPT_BLOCK_PADDING
+#define BCRYPT_BLOCK_PADDING 0x00000001
+#endif
+
+#ifndef BCRYPT_PAD_NONE
+#define BCRYPT_PAD_NONE 0x00000001
+#endif
+
+#ifndef BCRYPT_PAD_PKCS1
+#define BCRYPT_PAD_PKCS1 0x00000002
+#endif
+
+#ifndef BCRYPT_PAD_OAEP
+#define BCRYPT_PAD_OAEP 0x00000004
+#endif
+
+#ifndef BCRYPT_PAD_PSS
+#define BCRYPT_PAD_PSS 0x00000008
+#endif
+
+#ifndef CRYPT_STRING_ANY
+#define CRYPT_STRING_ANY 0x00000007
+#endif
+
+#ifndef LEGACY_RSAPRIVATE_BLOB
+#define LEGACY_RSAPRIVATE_BLOB L"CAPIPRIVATEBLOB"
+#endif
+
+#ifndef PKCS_RSA_PRIVATE_KEY
+#define PKCS_RSA_PRIVATE_KEY (LPCSTR)43
+#endif
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: Generic functions
+ */
+
+void
+_libssh2_wincng_init(void)
+{
+ int ret;
+
+ (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG,
+ BCRYPT_RNG_ALGORITHM, NULL, 0);
+
+ (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5,
+ BCRYPT_MD5_ALGORITHM, NULL, 0);
+ (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1,
+ BCRYPT_SHA1_ALGORITHM, NULL, 0);
+
+ (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5,
+ BCRYPT_MD5_ALGORITHM, NULL,
+ BCRYPT_ALG_HANDLE_HMAC_FLAG);
+ (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1,
+ BCRYPT_SHA1_ALGORITHM, NULL,
+ BCRYPT_ALG_HANDLE_HMAC_FLAG);
+
+ (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA,
+ BCRYPT_RSA_ALGORITHM, NULL, 0);
+ (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA,
+ BCRYPT_DSA_ALGORITHM, NULL, 0);
+
+ ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_CBC,
+ BCRYPT_AES_ALGORITHM, NULL, 0);
+ if (BCRYPT_SUCCESS(ret)) {
+ ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_CBC, BCRYPT_CHAINING_MODE,
+ (PBYTE)BCRYPT_CHAIN_MODE_CBC,
+ sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
+ }
+ }
+
+ ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRC4_NA,
+ BCRYPT_RC4_ALGORITHM, NULL, 0);
+ if (BCRYPT_SUCCESS(ret)) {
+ ret = BCryptSetProperty(_libssh2_wincng.hAlgRC4_NA, BCRYPT_CHAINING_MODE,
+ (PBYTE)BCRYPT_CHAIN_MODE_NA,
+ sizeof(BCRYPT_CHAIN_MODE_NA), 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
+ }
+ }
+
+ ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlg3DES_CBC,
+ BCRYPT_3DES_ALGORITHM, NULL, 0);
+ if (BCRYPT_SUCCESS(ret)) {
+ ret = BCryptSetProperty(_libssh2_wincng.hAlg3DES_CBC, BCRYPT_CHAINING_MODE,
+ (PBYTE)BCRYPT_CHAIN_MODE_CBC,
+ sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0);
+ }
+ }
+}
+
+void
+_libssh2_wincng_free(void)
+{
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRSA, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDSA, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
+ (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0);
+
+ memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng));
+}
+
+int
+_libssh2_wincng_random(void *buf, int len)
+{
+ int ret;
+
+ ret = BCryptGenRandom(_libssh2_wincng.hAlgRNG, buf, len, 0);
+
+ return BCRYPT_SUCCESS(ret) ? 0 : -1;
+}
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: Hash functions
+ */
+
+int
+_libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx,
+ BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen,
+ unsigned char *key, unsigned long keylen)
+{
+ BCRYPT_HASH_HANDLE hHash;
+ unsigned char *pbHashObject;
+ unsigned long dwHashObject, dwHash, cbData;
+ int ret;
+
+ ret = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH,
+ (unsigned char *)&dwHash,
+ sizeof(dwHash),
+ &cbData, 0);
+ if ((!BCRYPT_SUCCESS(ret)) || dwHash != hashlen) {
+ return -1;
+ }
+
+ ret = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH,
+ (unsigned char *)&dwHashObject,
+ sizeof(dwHashObject),
+ &cbData, 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ return -1;
+ }
+
+ pbHashObject = malloc(dwHashObject);
+ if (!pbHashObject) {
+ return -1;
+ }
+
+
+ ret = BCryptCreateHash(hAlg, &hHash,
+ pbHashObject, dwHashObject,
+ key, keylen, 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ free(pbHashObject);
+ return -1;
+ }
+
+
+ ctx->hHash = hHash;
+ ctx->pbHashObject = pbHashObject;
+ ctx->dwHashObject = dwHashObject;
+ ctx->cbHash = dwHash;
+
+ return 0;
+}
+
+int
+_libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx,
+ const unsigned char *data, unsigned long datalen)
+{
+ int ret;
+
+ ret = BCryptHashData(ctx->hHash, (unsigned char *)data, datalen, 0);
+
+ return BCRYPT_SUCCESS(ret) ? 0 : -1;
+}
+
+int
+_libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx,
+ unsigned char *hash)
+{
+ int ret;
+
+ ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0);
+
+ BCryptDestroyHash(ctx->hHash);
+
+ if (ctx->pbHashObject)
+ free(ctx->pbHashObject);
+
+ memset(ctx, 0, sizeof(_libssh2_wincng_hash_ctx));
+
+ return ret;
+}
+
+int
+_libssh2_wincng_hash(unsigned char *data, unsigned long datalen,
+ BCRYPT_ALG_HANDLE hAlg,
+ unsigned char *hash, unsigned long hashlen)
+{
+ _libssh2_wincng_hash_ctx ctx;
+
+ if (!_libssh2_wincng_hash_init(&ctx, hAlg, hashlen, NULL, 0)) {
+ if (!_libssh2_wincng_hash_update(&ctx, data, datalen)) {
+ if (!_libssh2_wincng_hash_final(&ctx, hash)) {
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: HMAC functions
+ */
+
+int
+_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx,
+ unsigned char *hash)
+{
+ int ret;
+
+ ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0);
+
+ return BCRYPT_SUCCESS(ret) ? 0 : -1;
+}
+
+void
+_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx)
+{
+ BCryptDestroyHash(ctx->hHash);
+
+ if (ctx->pbHashObject)
+ free(ctx->pbHashObject);
+
+ memset(ctx, 0, sizeof(_libssh2_wincng_hash_ctx));
+}
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: Key functions
+ */
+
+int
+_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx,
+ const unsigned char *sig,
+ unsigned long sig_len,
+ const unsigned char *m,
+ unsigned long m_len,
+ unsigned long flags)
+{
+ BCRYPT_PKCS1_PADDING_INFO paddingInfoPKCS1;
+ void *pPaddingInfo;
+ unsigned char *data, *hash;
+ unsigned long datalen, hashlen;
+ int ret;
+
+ datalen = m_len;
+ data = malloc(datalen);
+ if (!data) {
+ return -1;
+ }
+
+ hashlen = SHA_DIGEST_LENGTH;
+ hash = malloc(hashlen);
+ if (!hash) {
+ free(data);
+ return -1;
+ }
+
+ memcpy(data, m, datalen);
+
+ ret = _libssh2_wincng_hash(data, datalen,
+ _libssh2_wincng.hAlgHashSHA1,
+ hash, hashlen);
+
+ free(data);
+
+ if (ret) {
+ free(hash);
+ return -1;
+ }
+
+ datalen = sig_len;
+ data = malloc(datalen);
+ if (!data) {
+ free(hash);
+ return -1;
+ }
+
+ if (flags & BCRYPT_PAD_PKCS1) {
+ paddingInfoPKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM;
+ pPaddingInfo = &paddingInfoPKCS1;
+ } else
+ pPaddingInfo = NULL;
+
+ memcpy(data, sig, datalen);
+
+ ret = BCryptVerifySignature(ctx->hKey, pPaddingInfo,
+ hash, hashlen, data, datalen, flags);
+
+ free(hash);
+ free(data);
+
+ return BCRYPT_SUCCESS(ret) ? 0 : -1;
+}
+
+#ifdef HAVE_LIBCRYPT32
+static int
+_libssh2_wincng_load_pem(LIBSSH2_SESSION *session,
+ const char *filename,
+ const char *passphrase,
+ const char *headerbegin,
+ const char *headerend,
+ unsigned char **data,
+ unsigned int *datalen)
+{
+ FILE *fp;
+ int ret;
+
+ (void)passphrase;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ return -1;
+ }
+
+ ret = _libssh2_pem_parse(session, headerbegin, headerend,
+ fp, data, datalen);
+
+ fclose(fp);
+
+ return ret;
+}
+
+static int
+_libssh2_wincng_load_private(LIBSSH2_SESSION *session,
+ const char *filename,
+ const char *passphrase,
+ unsigned char **ppbEncoded,
+ unsigned long *pcbEncoded)
+{
+ unsigned char *data;
+ unsigned int datalen;
+ int ret;
+
+ ret = _libssh2_wincng_load_pem(session, filename, passphrase,
+ "-----BEGIN RSA PRIVATE KEY-----",
+ "-----END RSA PRIVATE KEY-----",
+ &data, &datalen);
+
+ if (ret) {
+ ret = _libssh2_wincng_load_pem(session, filename, passphrase,
+ "-----BEGIN DSA PRIVATE KEY-----",
+ "-----END DSA PRIVATE KEY-----",
+ &data, &datalen);
+ }
+
+ if (!ret) {
+ *ppbEncoded = data;
+ *pcbEncoded = datalen;
+ }
+
+ return ret;
+}
+
+static int
+_libssh2_wincng_asn_decode(unsigned char *pbEncoded,
+ unsigned long cbEncoded,
+ LPCSTR lpszStructType,
+ unsigned char **ppbDecoded,
+ unsigned long *pcbDecoded)
+{
+ unsigned char *pbDecoded = NULL;
+ unsigned long cbDecoded = 0;
+ int ret;
+
+ ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ lpszStructType,
+ pbEncoded, cbEncoded, 0, NULL,
+ NULL, &cbDecoded);
+ if (!ret) {
+ return -1;
+ }
+
+ pbDecoded = malloc(cbDecoded);
+ if (!pbDecoded) {
+ return -1;
+ }
+
+ ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ lpszStructType,
+ pbEncoded, cbEncoded, 0, NULL,
+ pbDecoded, &cbDecoded);
+ if (!ret) {
+ free(pbDecoded);
+ return -1;
+ }
+
+
+ *ppbDecoded = pbDecoded;
+ *pcbDecoded = cbDecoded;
+
+ return 0;
+}
+
+static int
+_libssh2_wincng_bn_ltob(unsigned char *pbInput,
+ unsigned long cbInput,
+ unsigned char **ppbOutput,
+ unsigned long *pcbOutput)
+{
+ unsigned char *pbOutput;
+ unsigned long cbOutput, index, offset, length;
+
+ if (cbInput < 1) {
+ return 0;
+ }
+
+ offset = 0;
+ length = cbInput - 1;
+ cbOutput = cbInput;
+ if (pbInput[length] & (1 << 7)) {
+ offset++;
+ cbOutput += offset;
+ }
+
+ pbOutput = (unsigned char *)malloc(cbOutput);
+ if (!pbOutput) {
+ return -1;
+ }
+
+ pbOutput[0] = 0;
+ for (index = 0; ((index + offset) < cbOutput)
+ && (index < cbInput); index++) {
+ pbOutput[index + offset] = pbInput[length - index];
+ }
+
+
+ *ppbOutput = pbOutput;
+ *pcbOutput = cbOutput;
+
+ return 0;
+}
+
+static int
+_libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded,
+ unsigned long cbEncoded,
+ unsigned char **ppbDecoded,
+ unsigned long *pcbDecoded)
+{
+ unsigned char *pbDecoded = NULL, *pbInteger;
+ unsigned long cbDecoded = 0, cbInteger;
+ int ret;
+
+ ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
+ X509_MULTI_BYTE_UINT,
+ &pbInteger, &cbInteger);
+ if (!ret) {
+ ret = _libssh2_wincng_bn_ltob(((PCRYPT_DATA_BLOB)pbInteger)->pbData,
+ ((PCRYPT_DATA_BLOB)pbInteger)->cbData,
+ &pbDecoded, &cbDecoded);
+ if (!ret) {
+ *ppbDecoded = pbDecoded;
+ *pcbDecoded = cbDecoded;
+ }
+ free(pbInteger);
+ }
+
+ return ret;
+}
+
+static int
+_libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded,
+ unsigned long cbEncoded,
+ unsigned char ***prpbDecoded,
+ unsigned long **prcbDecoded,
+ unsigned long *pcbCount)
+{
+ PCRYPT_DER_BLOB pBlob;
+ unsigned char *pbDecoded, **rpbDecoded;
+ unsigned long cbDecoded, *rcbDecoded, index, length;
+ int ret;
+
+ ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
+ X509_SEQUENCE_OF_ANY,
+ &pbDecoded, &cbDecoded);
+ if (!ret) {
+ length = ((PCRYPT_DATA_BLOB)pbDecoded)->cbData;
+
+ rpbDecoded = malloc(sizeof(PBYTE) * length);
+ if (rpbDecoded) {
+ rcbDecoded = malloc(sizeof(DWORD) * length);
+ if (rcbDecoded) {
+ for (index = 0; index < length; index++) {
+ pBlob = &((PCRYPT_DER_BLOB)
+ ((PCRYPT_DATA_BLOB)pbDecoded)->pbData)[index];
+ ret = _libssh2_wincng_asn_decode_bn(pBlob->pbData,
+ pBlob->cbData,
+ &rpbDecoded[index],
+ &rcbDecoded[index]);
+ if (ret)
+ break;
+ }
+
+ if (!ret) {
+ *prpbDecoded = rpbDecoded;
+ *prcbDecoded = rcbDecoded;
+ *pcbCount = length;
+ } else {
+ for (length = 0; length < index; length++) {
+ if (rpbDecoded[length]) {
+ free(rpbDecoded[length]);
+ rpbDecoded[length] = NULL;
+ }
+ }
+ free(rpbDecoded);
+ free(rcbDecoded);
+ }
+ } else {
+ free(rpbDecoded);
+ ret = -1;
+ }
+ } else {
+ ret = -1;
+ }
+
+ free(pbDecoded);
+ }
+
+ return ret;
+}
+#endif /* HAVE_LIBCRYPT32 */
+
+static unsigned long
+_libssh2_wincng_bn_size(const unsigned char *bignum,
+ unsigned long length)
+{
+ unsigned long offset;
+
+ if (!bignum)
+ return 0;
+
+ length--;
+
+ offset = 0;
+ while (!(*(bignum + offset)) && (offset < length))
+ offset++;
+
+ length++;
+
+ return length - offset;
+}
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: RSA functions
+ */
+
+int
+_libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa,
+ const unsigned char *edata,
+ unsigned long elen,
+ const unsigned char *ndata,
+ unsigned long nlen,
+ const unsigned char *ddata,
+ unsigned long dlen,
+ const unsigned char *pdata,
+ unsigned long plen,
+ const unsigned char *qdata,
+ unsigned long qlen,
+ const unsigned char *e1data,
+ unsigned long e1len,
+ const unsigned char *e2data,
+ unsigned long e2len,
+ const unsigned char *coeffdata,
+ unsigned long coefflen)
+{
+ BCRYPT_KEY_HANDLE hKey;
+ BCRYPT_RSAKEY_BLOB *rsakey;
+ LPCWSTR lpszBlobType;
+ unsigned char *key;
+ unsigned long keylen, offset, mlen, p1len = 0, p2len = 0;
+ int ret;
+
+ mlen = max(_libssh2_wincng_bn_size(ndata, nlen),
+ _libssh2_wincng_bn_size(ddata, dlen));
+ offset = sizeof(BCRYPT_RSAKEY_BLOB);
+ keylen = offset + elen + mlen;
+ if (ddata && dlen > 0) {
+ p1len = max(_libssh2_wincng_bn_size(pdata, plen),
+ _libssh2_wincng_bn_size(e1data, e1len));
+ p2len = max(_libssh2_wincng_bn_size(qdata, qlen),
+ _libssh2_wincng_bn_size(e2data, e2len));
+ keylen += p1len * 3 + p2len * 2 + mlen;
+ }
+
+ key = malloc(keylen);
+ if (!key) {
+ return -1;
+ }
+
+ memset(key, 0, keylen);
+
+
+ /* http://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */
+ rsakey = (BCRYPT_RSAKEY_BLOB *)key;
+ rsakey->BitLength = mlen * 8;
+ rsakey->cbPublicExp = elen;
+ rsakey->cbModulus = mlen;
+
+ memcpy(key + offset, edata, elen);
+ offset += elen;
+
+ if (nlen < mlen)
+ memcpy(key + offset + mlen - nlen, ndata, nlen);
+ else
+ memcpy(key + offset, ndata + nlen - mlen, mlen);
+
+ if (ddata && dlen > 0) {
+ offset += mlen;
+
+ if (plen < p1len)
+ memcpy(key + offset + p1len - plen, pdata, plen);
+ else
+ memcpy(key + offset, pdata + plen - p1len, p1len);
+ offset += p1len;
+
+ if (qlen < p2len)
+ memcpy(key + offset + p2len - qlen, qdata, qlen);
+ else
+ memcpy(key + offset, qdata + qlen - p2len, p2len);
+ offset += p2len;
+
+ if (e1len < p1len)
+ memcpy(key + offset + p1len - e1len, e1data, e1len);
+ else
+ memcpy(key + offset, e1data + e1len - p1len, p1len);
+ offset += p1len;
+
+ if (e2len < p2len)
+ memcpy(key + offset + p2len - e2len, e2data, e2len);
+ else
+ memcpy(key + offset, e2data + e2len - p2len, p2len);
+ offset += p2len;
+
+ if (coefflen < p1len)
+ memcpy(key + offset + p1len - coefflen, coeffdata, coefflen);
+ else
+ memcpy(key + offset, coeffdata + coefflen - p1len, p1len);
+ offset += p1len;
+
+ if (dlen < mlen)
+ memcpy(key + offset + mlen - dlen, ddata, dlen);
+ else
+ memcpy(key + offset, ddata + dlen - mlen, mlen);
+
+ lpszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB;
+ rsakey->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC;
+ rsakey->cbPrime1 = p1len;
+ rsakey->cbPrime2 = p2len;
+ } else {
+ lpszBlobType = BCRYPT_RSAPUBLIC_BLOB;
+ rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC;
+ rsakey->cbPrime1 = 0;
+ rsakey->cbPrime2 = 0;
+ }
+
+
+ ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType,
+ &hKey, key, keylen, 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ free(key);
+ return -1;
+ }
+
+
+ *rsa = malloc(sizeof(libssh2_rsa_ctx));
+ if (!(*rsa)) {
+ BCryptDestroyKey(hKey);
+ free(key);
+ return -1;
+ }
+
+ (*rsa)->hKey = hKey;
+ (*rsa)->pbKeyObject = key;
+ (*rsa)->cbKeyObject = keylen;
+
+ return 0;
+}
+
+int
+_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa,
+ LIBSSH2_SESSION *session,
+ const char *filename,
+ const unsigned char *passphrase)
+{
+#ifdef HAVE_LIBCRYPT32
+ BCRYPT_KEY_HANDLE hKey;
+ unsigned char *pbEncoded, *pbStructInfo;
+ unsigned long cbEncoded, cbStructInfo;
+ int ret;
+
+ (void)session;
+
+ ret = _libssh2_wincng_load_private(session, filename,
+ (const char *)passphrase,
+ &pbEncoded, &cbEncoded);
+ if (ret) {
+ return -1;
+ }
+
+ ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
+ PKCS_RSA_PRIVATE_KEY,
+ &pbStructInfo, &cbStructInfo);
+
+ free(pbEncoded);
+
+ if (ret) {
+ return -1;
+ }
+
+
+ ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL,
+ LEGACY_RSAPRIVATE_BLOB, &hKey,
+ pbStructInfo, cbStructInfo, 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ free(pbStructInfo);
+ return -1;
+ }
+
+
+ *rsa = malloc(sizeof(libssh2_rsa_ctx));
+ if (!(*rsa)) {
+ BCryptDestroyKey(hKey);
+ free(pbStructInfo);
+ return -1;
+ }
+
+ (*rsa)->hKey = hKey;
+ (*rsa)->pbKeyObject = pbStructInfo;
+ (*rsa)->cbKeyObject = cbStructInfo;
+
+ return 0;
+#else
+ (void)rsa;
+ (void)filename;
+ (void)passphrase;
+
+ return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to load RSA key from private key file: "
+ "Method unsupported in Windows CNG backend");
+#endif /* HAVE_LIBCRYPT32 */
+}
+
+int
+_libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
+ const unsigned char *sig,
+ unsigned long sig_len,
+ const unsigned char *m,
+ unsigned long m_len)
+{
+ return _libssh2_wincng_key_sha1_verify(rsa, sig, sig_len, m, m_len,
+ BCRYPT_PAD_PKCS1);
+}
+
+int
+_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session,
+ libssh2_rsa_ctx *rsa,
+ const unsigned char *hash,
+ size_t hash_len,
+ unsigned char **signature,
+ size_t *signature_len)
+{
+ BCRYPT_PKCS1_PADDING_INFO paddingInfo;
+ unsigned char *data, *sig;
+ unsigned long cbData, datalen, siglen;
+ int ret;
+
+ datalen = (unsigned long)hash_len;
+ data = malloc(datalen);
+ if (!data) {
+ return -1;
+ }
+
+ paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
+
+ memcpy(data, hash, datalen);
+
+ ret = BCryptSignHash(rsa->hKey, &paddingInfo,
+ data, datalen, NULL, 0,
+ &cbData, BCRYPT_PAD_PKCS1);
+ if (BCRYPT_SUCCESS(ret)) {
+ siglen = cbData;
+ sig = LIBSSH2_ALLOC(session, siglen);
+ if (sig) {
+ ret = BCryptSignHash(rsa->hKey, &paddingInfo,
+ data, datalen, sig, siglen,
+ &cbData, BCRYPT_PAD_PKCS1);
+ if (BCRYPT_SUCCESS(ret)) {
+ *signature_len = siglen;
+ *signature = sig;
+ } else {
+ LIBSSH2_FREE(session, sig);
+ }
+ } else
+ ret = STATUS_NO_MEMORY;
+ }
+
+ free(data);
+
+ return BCRYPT_SUCCESS(ret) ? 0 : -1;
+}
+
+void
+_libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa)
+{
+ if (!rsa)
+ return;
+
+ BCryptDestroyKey(rsa->hKey);
+
+ if (rsa->pbKeyObject)
+ free(rsa->pbKeyObject);
+
+ memset(rsa, 0, sizeof(libssh2_rsa_ctx));
+ free(rsa);
+}
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: DSA functions
+ */
+
+#if LIBSSH2_DSA
+int
+_libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa,
+ const unsigned char *pdata,
+ unsigned long plen,
+ const unsigned char *qdata,
+ unsigned long qlen,
+ const unsigned char *gdata,
+ unsigned long glen,
+ const unsigned char *ydata,
+ unsigned long ylen,
+ const unsigned char *xdata,
+ unsigned long xlen)
+{
+ BCRYPT_KEY_HANDLE hKey;
+ BCRYPT_DSA_KEY_BLOB *dsakey;
+ LPCWSTR lpszBlobType;
+ unsigned char *key;
+ unsigned long keylen, offset, length;
+ int ret;
+
+ length = max(max(_libssh2_wincng_bn_size(pdata, plen),
+ _libssh2_wincng_bn_size(gdata, glen)),
+ _libssh2_wincng_bn_size(ydata, ylen));
+ offset = sizeof(BCRYPT_DSA_KEY_BLOB);
+ keylen = offset + length * 3;
+ if (xdata && xlen > 0)
+ keylen += 20;
+
+ key = malloc(keylen);
+ if (!key) {
+ return -1;
+ }
+
+ memset(key, 0, keylen);
+
+
+ /* http://msdn.microsoft.com/library/windows/desktop/aa833126.aspx */
+ dsakey = (BCRYPT_DSA_KEY_BLOB *)key;
+ dsakey->cbKey = length;
+
+ memset(dsakey->Count, -1, sizeof(dsakey->Count));
+ memset(dsakey->Seed, -1, sizeof(dsakey->Seed));
+
+ if (qlen < 20)
+ memcpy(dsakey->q + 20 - qlen, qdata, qlen);
+ else
+ memcpy(dsakey->q, qdata + qlen - 20, 20);
+
+ if (plen < length)
+ memcpy(key + offset + length - plen, pdata, plen);
+ else
+ memcpy(key + offset, pdata + plen - length, length);
+ offset += length;
+
+ if (glen < length)
+ memcpy(key + offset + length - glen, gdata, glen);
+ else
+ memcpy(key + offset, gdata + glen - length, length);
+ offset += length;
+
+ if (ylen < length)
+ memcpy(key + offset + length - ylen, ydata, ylen);
+ else
+ memcpy(key + offset, ydata + ylen - length, length);
+
+ if (xdata && xlen > 0) {
+ offset += length;
+
+ if (xlen < 20)
+ memcpy(key + offset + 20 - xlen, xdata, xlen);
+ else
+ memcpy(key + offset, xdata + xlen - 20, 20);
+
+ lpszBlobType = BCRYPT_DSA_PRIVATE_BLOB;
+ dsakey->dwMagic = BCRYPT_DSA_PRIVATE_MAGIC;
+ } else {
+ lpszBlobType = BCRYPT_DSA_PUBLIC_BLOB;
+ dsakey->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC;
+ }
+
+
+ ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType,
+ &hKey, key, keylen, 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ free(key);
+ return -1;
+ }
+
+
+ *dsa = malloc(sizeof(libssh2_dsa_ctx));
+ if (!(*dsa)) {
+ BCryptDestroyKey(hKey);
+ free(key);
+ return -1;
+ }
+
+ (*dsa)->hKey = hKey;
+ (*dsa)->pbKeyObject = key;
+ (*dsa)->cbKeyObject = keylen;
+
+ return 0;
+}
+
+int
+_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa,
+ LIBSSH2_SESSION *session,
+ const char *filename,
+ const unsigned char *passphrase)
+{
+#ifdef HAVE_LIBCRYPT32
+ unsigned char *pbEncoded, **rpbDecoded;
+ unsigned long cbEncoded, *rcbDecoded, index, length;
+ int ret;
+
+ (void)session;
+
+ ret = _libssh2_wincng_load_private(session, filename,
+ (const char *)passphrase,
+ &pbEncoded, &cbEncoded);
+ if (ret) {
+ return -1;
+ }
+
+ ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded,
+ &rpbDecoded, &rcbDecoded, &length);
+
+ free(pbEncoded);
+
+ if (ret) {
+ return -1;
+ }
+
+
+ if (length == 6) {
+ ret = _libssh2_wincng_dsa_new(dsa,
+ rpbDecoded[1], rcbDecoded[1],
+ rpbDecoded[2], rcbDecoded[2],
+ rpbDecoded[3], rcbDecoded[3],
+ rpbDecoded[4], rcbDecoded[4],
+ rpbDecoded[5], rcbDecoded[5]);
+ } else {
+ ret = -1;
+ }
+
+ for (index = 0; index < length; index++) {
+ if (rpbDecoded[index]) {
+ free(rpbDecoded[index]);
+ rpbDecoded[index] = NULL;
+ }
+ }
+
+ free(rpbDecoded);
+ free(rcbDecoded);
+
+ return ret;
+#else
+ (void)dsa;
+ (void)filename;
+ (void)passphrase;
+
+ return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to load DSA key from private key file: "
+ "Method unsupported in Windows CNG backend");
+#endif /* HAVE_LIBCRYPT32 */
+}
+
+int
+_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa,
+ const unsigned char *sig_fixed,
+ const unsigned char *m,
+ unsigned long m_len)
+{
+ return _libssh2_wincng_key_sha1_verify(dsa, sig_fixed, 40, m, m_len, 0);
+}
+
+int
+_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa,
+ const unsigned char *hash,
+ unsigned long hash_len,
+ unsigned char *sig_fixed)
+{
+ unsigned char *data, *sig;
+ unsigned long cbData, datalen, siglen;
+ int ret;
+
+ datalen = hash_len;
+ data = malloc(datalen);
+ if (!data) {
+ return -1;
+ }
+
+ memcpy(data, hash, datalen);
+
+ ret = BCryptSignHash(dsa->hKey, NULL, data, datalen,
+ NULL, 0, &cbData, 0);
+ if (BCRYPT_SUCCESS(ret)) {
+ siglen = cbData;
+ if (siglen == 40) {
+ sig = malloc(siglen);
+ if (sig) {
+ ret = BCryptSignHash(dsa->hKey, NULL, data, datalen,
+ sig, siglen, &cbData, 0);
+ if (BCRYPT_SUCCESS(ret)) {
+ memcpy(sig_fixed, sig, siglen);
+ }
+
+ free(sig);
+ } else
+ ret = STATUS_NO_MEMORY;
+ } else
+ ret = STATUS_NO_MEMORY;
+ }
+
+ free(data);
+
+ return BCRYPT_SUCCESS(ret) ? 0 : -1;
+}
+
+void
+_libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa)
+{
+ if (!dsa)
+ return;
+
+ BCryptDestroyKey(dsa->hKey);
+
+ if (dsa->pbKeyObject)
+ free(dsa->pbKeyObject);
+
+ memset(dsa, 0, sizeof(libssh2_dsa_ctx));
+ free(dsa);
+}
+#endif
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: Key functions
+ */
+
+static unsigned long
+_libssh2_wincng_pub_priv_write(unsigned char *key,
+ unsigned long offset,
+ const unsigned char *bignum,
+ const unsigned long length)
+{
+ _libssh2_htonu32(key + offset, length);
+ offset += 4;
+
+ memcpy(key + offset, bignum, length);
+ offset += length;
+
+ return offset;
+}
+
+int
+_libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ const char *privatekey,
+ const char *passphrase)
+{
+#ifdef HAVE_LIBCRYPT32
+ unsigned char *pbEncoded, **rpbDecoded;
+ unsigned long cbEncoded, *rcbDecoded;
+ unsigned char *key = NULL, *mth = NULL;
+ unsigned long keylen = 0, mthlen = 0;
+ unsigned long index, offset, length;
+ int ret;
+
+ ret = _libssh2_wincng_load_private(session, privatekey, passphrase,
+ &pbEncoded, &cbEncoded);
+ if (ret) {
+ return -1;
+ }
+
+ ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded,
+ &rpbDecoded, &rcbDecoded, &length);
+
+ free(pbEncoded);
+
+ if (ret) {
+ return -1;
+ }
+
+
+ if (length == 9) { /* private RSA key */
+ mthlen = 7;
+ mth = LIBSSH2_ALLOC(session, mthlen);
+ if (mth) {
+ memcpy(mth, "ssh-rsa", mthlen);
+ } else {
+ ret = -1;
+ }
+
+
+ keylen = 4 + mthlen + 4 + rcbDecoded[2] + 4 + rcbDecoded[1];
+ key = LIBSSH2_ALLOC(session, keylen);
+ if (key) {
+ offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen);
+
+ offset = _libssh2_wincng_pub_priv_write(key, offset,
+ rpbDecoded[2],
+ rcbDecoded[2]);
+
+ _libssh2_wincng_pub_priv_write(key, offset,
+ rpbDecoded[1],
+ rcbDecoded[1]);
+ } else {
+ ret = -1;
+ }
+
+ } else if (length == 6) { /* private DSA key */
+ mthlen = 7;
+ mth = LIBSSH2_ALLOC(session, mthlen);
+ if (mth) {
+ memcpy(mth, "ssh-dss", mthlen);
+ } else {
+ ret = -1;
+ }
+
+ keylen = 4 + mthlen + 4 + rcbDecoded[1] + 4 + rcbDecoded[2]
+ + 4 + rcbDecoded[3] + 4 + rcbDecoded[4];
+ key = LIBSSH2_ALLOC(session, keylen);
+ if (key) {
+ offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen);
+
+ offset = _libssh2_wincng_pub_priv_write(key, offset,
+ rpbDecoded[1],
+ rcbDecoded[1]);
+
+ offset = _libssh2_wincng_pub_priv_write(key, offset,
+ rpbDecoded[2],
+ rcbDecoded[2]);
+
+ offset = _libssh2_wincng_pub_priv_write(key, offset,
+ rpbDecoded[3],
+ rcbDecoded[3]);
+
+ _libssh2_wincng_pub_priv_write(key, offset,
+ rpbDecoded[4],
+ rcbDecoded[4]);
+ } else {
+ ret = -1;
+ }
+
+ } else {
+ ret = -1;
+ }
+
+
+ for (index = 0; index < length; index++) {
+ if (rpbDecoded[index]) {
+ free(rpbDecoded[index]);
+ rpbDecoded[index] = NULL;
+ }
+ }
+
+ free(rpbDecoded);
+ free(rcbDecoded);
+
+
+ if (ret) {
+ if (mth)
+ LIBSSH2_FREE(session, mth);
+ if (key)
+ LIBSSH2_FREE(session, key);
+ } else {
+ *method = mth;
+ *method_len = mthlen;
+ *pubkeydata = key;
+ *pubkeydata_len = keylen;
+ }
+
+ return ret;
+#else
+ (void)method;
+ (void)method_len;
+ (void)pubkeydata;
+ (void)pubkeydata_len;
+ (void)privatekey;
+ (void)passphrase;
+
+ return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to load public key from private key file: "
+ "Method unsupported in Windows CNG backend");
+#endif /* HAVE_LIBCRYPT32 */
+}
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: Cipher functions
+ */
+
+int
+_libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx,
+ _libssh2_cipher_type(type),
+ unsigned char *iv,
+ unsigned char *secret,
+ int encrypt)
+{
+ BCRYPT_KEY_HANDLE hKey;
+ BCRYPT_KEY_DATA_BLOB_HEADER *header;
+ unsigned char *pbKeyObject, *pbIV, *key;
+ unsigned long dwKeyObject, dwIV, dwBlockLength, cbData, keylen;
+ int ret;
+
+ (void)encrypt;
+
+ ret = BCryptGetProperty(*type.phAlg, BCRYPT_OBJECT_LENGTH,
+ (unsigned char *)&dwKeyObject,
+ sizeof(dwKeyObject),
+ &cbData, 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ return -1;
+ }
+
+ ret = BCryptGetProperty(*type.phAlg, BCRYPT_BLOCK_LENGTH,
+ (unsigned char *)&dwBlockLength,
+ sizeof(dwBlockLength),
+ &cbData, 0);
+ if (!BCRYPT_SUCCESS(ret)) {
+ return -1;
+ }
+
+ pbKeyObject = malloc(dwKeyObject);
+ if (!pbKeyObject) {
+ return -1;
+ }
+
+
+ keylen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + type.dwKeyLength;
+ key = malloc(keylen);
+ if (!key) {
+ free(pbKeyObject);
+ return -1;
+ }
+
+
+ header = (BCRYPT_KEY_DATA_BLOB_HEADER *)key;
+ header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
+ header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
+ header->cbKeyData = type.dwKeyLength;
+
+ memcpy(key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER),
+ secret, type.dwKeyLength);
+
+ ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey,
+ pbKeyObject, dwKeyObject, key, keylen, 0);
+
+ free(key);
+
+ if (!BCRYPT_SUCCESS(ret)) {
+ free(pbKeyObject);
+ return -1;
+ }
+
+ if (type.dwUseIV) {
+ pbIV = malloc(dwBlockLength);
+ if (!pbIV) {
+ BCryptDestroyKey(hKey);
+ free(pbKeyObject);
+ return -1;
+ }
+ dwIV = dwBlockLength;
+ memcpy(pbIV, iv, dwIV);
+ } else {
+ pbIV = NULL;
+ dwIV = 0;
+ }
+
+
+ ctx->hKey = hKey;
+ ctx->pbKeyObject = pbKeyObject;
+ ctx->pbIV = pbIV;
+ ctx->dwKeyObject = dwKeyObject;
+ ctx->dwIV = dwIV;
+ ctx->dwBlockLength = dwBlockLength;
+
+ return 0;
+}
+
+int
+_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx,
+ _libssh2_cipher_type(type),
+ int encrypt,
+ unsigned char *block,
+ size_t blocklen)
+{
+ unsigned char *pbOutput;
+ unsigned long cbOutput, cbInput;
+ int ret;
+
+ (void)type;
+
+ cbInput = (unsigned long)blocklen;
+
+ if (encrypt) {
+ ret = BCryptEncrypt(ctx->hKey, block, cbInput, NULL,
+ ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0);
+ } else {
+ ret = BCryptDecrypt(ctx->hKey, block, cbInput, NULL,
+ ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0);
+ }
+ if (BCRYPT_SUCCESS(ret)) {
+ pbOutput = malloc(cbOutput);
+ if (pbOutput) {
+ if (encrypt) {
+ ret = BCryptEncrypt(ctx->hKey, block, cbInput, NULL,
+ ctx->pbIV, ctx->dwIV,
+ pbOutput, cbOutput, &cbOutput, 0);
+ } else {
+ ret = BCryptDecrypt(ctx->hKey, block, cbInput, NULL,
+ ctx->pbIV, ctx->dwIV,
+ pbOutput, cbOutput, &cbOutput, 0);
+ }
+ if (BCRYPT_SUCCESS(ret)) {
+ memcpy(block, pbOutput, cbOutput);
+ }
+
+ free(pbOutput);
+ } else
+ ret = STATUS_NO_MEMORY;
+ }
+
+ return BCRYPT_SUCCESS(ret) ? 0 : -1;
+}
+
+void
+_libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx)
+{
+ BCryptDestroyKey(ctx->hKey);
+
+ if (ctx->pbKeyObject) {
+ free(ctx->pbKeyObject);
+ ctx->pbKeyObject = NULL;
+ }
+
+ memset(ctx, 0, sizeof(_libssh2_cipher_ctx));
+}
+
+
+/*******************************************************************/
+/*
+ * Windows CNG backend: BigNumber functions
+ */
+
+_libssh2_bn *
+_libssh2_wincng_bignum_init(void)
+{
+ _libssh2_bn *bignum;
+
+ bignum = (_libssh2_bn *)malloc(sizeof(_libssh2_bn));
+ if (bignum) {
+ bignum->bignum = NULL;
+ bignum->length = 0;
+ }
+
+ return bignum;
+}
+
+static int
+_libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length)
+{
+ unsigned char *bignum;
+
+ if (!bn)
+ return -1;
+
+ if (length == bn->length)
+ return 0;
+
+ bignum = realloc(bn->bignum, length);
+ if (!bignum)
+ return -1;
+
+ bn->bignum = bignum;
+ bn->length = length;
+
+ return 0;
+}
+
+int
+_libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom)
+{
+ unsigned char *bignum;
+ unsigned long length;
+
+ if (!rnd)
+ return -1;
+
+ length = (unsigned long)(ceil((float)bits / 8) * sizeof(unsigned char));
+ if (_libssh2_wincng_bignum_resize(rnd, length))
+ return -1;
+
+ bignum = rnd->bignum;
+
+ if (_libssh2_wincng_random(bignum, length))
+ return -1;
+
+ /* calculate significant bits in most significant byte */
+ bits %= 8;
+
+ /* fill most significant byte with zero padding */
+ bignum[0] &= (1 << (8 - bits)) - 1;
+
+ /* set some special last bits in most significant byte */
+ if (top == 0)
+ bignum[0] |= (1 << (7 - bits));
+ else if (top == 1)
+ bignum[0] |= (3 << (6 - bits));
+
+ /* make odd by setting first bit in least significant byte */
+ if (bottom)
+ bignum[length - 1] |= 1;
+
+ return 0;
+}
+
+int
+_libssh2_wincng_bignum_mod_exp(_libssh2_bn *r,
+ _libssh2_bn *a,
+ _libssh2_bn *p,
+ _libssh2_bn *m,
+ _libssh2_bn_ctx *bnctx)
+{
+ BCRYPT_KEY_HANDLE hKey;
+ BCRYPT_RSAKEY_BLOB *rsakey;
+ unsigned char *key, *bignum;
+ unsigned long keylen, offset, length;
+ int ret;
+
+ (void)bnctx;
+
+ if (!r || !a || !p || !m)
+ return -1;
+
+ offset = sizeof(BCRYPT_RSAKEY_BLOB);
+ keylen = offset + p->length + m->length;
+
+ key = malloc(keylen);
+ if (!key)
+ return -1;
+
+
+ /* http://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */
+ rsakey = (BCRYPT_RSAKEY_BLOB *)key;
+ rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC;
+ rsakey->BitLength = m->length * 8;
+ rsakey->cbPublicExp = p->length;
+ rsakey->cbModulus = m->length;
+ rsakey->cbPrime1 = 0;
+ rsakey->cbPrime2 = 0;
+
+ memcpy(key + offset, p->bignum, p->length);
+ offset += p->length;
+
+ memcpy(key + offset, m->bignum, m->length);
+
+ ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL,
+ BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen,
+ BCRYPT_NO_KEY_VALIDATION);
+
+ if (BCRYPT_SUCCESS(ret)) {
+ ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0,
+ NULL, 0, &length, BCRYPT_PAD_NONE);
+ if (BCRYPT_SUCCESS(ret)) {
+ if (!_libssh2_wincng_bignum_resize(r, length)) {
+ length = max(a->length, length);
+ bignum = malloc(length);
+ if (bignum) {
+ offset = length - a->length;
+ memset(bignum, 0, offset);
+ memcpy(bignum + offset, a->bignum, a->length);
+
+ ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0,
+ r->bignum, r->length, &offset,
+ BCRYPT_PAD_NONE);
+
+ free(bignum);
+
+ if (BCRYPT_SUCCESS(ret)) {
+ _libssh2_wincng_bignum_resize(r, offset);
+ }
+ } else
+ ret = STATUS_NO_MEMORY;
+ } else
+ ret = STATUS_NO_MEMORY;
+ }
+
+ BCryptDestroyKey(hKey);
+ }
+
+ free(key);
+
+ return BCRYPT_SUCCESS(ret) ? 0 : -1;
+}
+
+int
+_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word)
+{
+ unsigned long offset, number, bits, length;
+
+ if (!bn)
+ return -1;
+
+ bits = 0;
+ number = word;
+ while (number >>= 1)
+ bits++;
+
+ length = (unsigned long) (ceil(((double)(bits + 1)) / 8.0) *
+ sizeof(unsigned char));
+ if (_libssh2_wincng_bignum_resize(bn, length))
+ return -1;
+
+ for (offset = 0; offset < length; offset++)
+ bn->bignum[offset] = (word >> (offset * 8)) & 0xff;
+
+ return 0;
+}
+
+unsigned long
+_libssh2_wincng_bignum_bits(const _libssh2_bn *bn)
+{
+ unsigned char number;
+ unsigned long offset, length, bits;
+
+ if (!bn)
+ return 0;
+
+ length = bn->length - 1;
+
+ offset = 0;
+ while (!(*(bn->bignum + offset)) && (offset < length))
+ offset++;
+
+ bits = (length - offset) * 8;
+ number = bn->bignum[offset];
+
+ while (number >>= 1)
+ bits++;
+
+ bits++;
+
+ return bits;
+}
+
+void
+_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len,
+ const unsigned char *bin)
+{
+ unsigned char *bignum;
+ unsigned long offset, length, bits;
+
+ if (!bn || !bin || !len)
+ return;
+
+ if (_libssh2_wincng_bignum_resize(bn, len))
+ return;
+
+ memcpy(bn->bignum, bin, len);
+
+ bits = _libssh2_wincng_bignum_bits(bn);
+ length = (unsigned long) (ceil(((double)bits) / 8.0) *
+ sizeof(unsigned char));
+
+ offset = bn->length - length;
+ if (offset > 0) {
+ memmove(bn->bignum, bn->bignum + offset, length);
+
+ bignum = realloc(bn->bignum, length);
+ if (bignum) {
+ bn->bignum = bignum;
+ bn->length = length;
+ }
+ }
+}
+
+void
+_libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin)
+{
+ if (bin && bn && bn->bignum && bn->length > 0) {
+ memcpy(bin, bn->bignum, bn->length);
+ }
+}
+
+void
+_libssh2_wincng_bignum_free(_libssh2_bn *bn)
+{
+ if (bn) {
+ if (bn->bignum) {
+ free(bn->bignum);
+ bn->bignum = NULL;
+ }
+ bn->length = 0;
+ free(bn);
+ }
+}
+
+
+/*
+ * Windows CNG backend: other functions
+ */
+
+void _libssh2_init_aes_ctr(void)
+{
+ /* no implementation */
+ (void)0;
+}
+
+#endif /* LIBSSH2_WINCNG */