From 7f8594fe6e6e9d91dcadbbea09f0e40d7cd937c9 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 10 Nov 2003 11:25:43 +0000 Subject: [PATCH] Rewrote the PKCS#1 routines. Removed the Mozilla's PKCS#1 routines from SILC distributions. --- CHANGES | 9 +- includes/silcincludes.h.in | 1 + lib/silccrypt/DIRECTORY | 2 +- lib/silccrypt/Makefile.am | 13 +- lib/silccrypt/pkcs1.c | 475 ------------------------------------- lib/silccrypt/pkcs1.h | 35 --- lib/silccrypt/rsa.c | 163 +++++++++++++ lib/silccrypt/rsa.h | 14 +- lib/silccrypt/silcpkcs.c | 1 - lib/silccrypt/silcpkcs1.c | 149 ++++++++++++ lib/silccrypt/silcpkcs1.h | 115 +++++++++ 11 files changed, 452 insertions(+), 525 deletions(-) delete mode 100644 lib/silccrypt/pkcs1.c delete mode 100644 lib/silccrypt/pkcs1.h create mode 100644 lib/silccrypt/silcpkcs1.c create mode 100644 lib/silccrypt/silcpkcs1.h diff --git a/CHANGES b/CHANGES index 23c5cba4..fdbf8bf3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,11 @@ -Sun Nov 9 20:44:56 EET 200 Pekka Riikonen +Mon Nov 10 13:03:46 EET 2003 Pekka Riikonen + + * Rewrote the PKCS#1 routines. Added lib/silccrypt/silcpkcs1.[ch]. + + * The SILC RNG is now gauranteed to return non-zero random + values. Affected files are lib/silccrypt/silcrng.[ch]. + +Sun Nov 9 20:44:56 EET 2003 Pekka Riikonen * Fixed nickname formatting when changing only case of the nickname. Affected file lib/silcclient/idlist.c. diff --git a/includes/silcincludes.h.in b/includes/silcincludes.h.in index 65bf8bdb..0d923e45 100644 --- a/includes/silcincludes.h.in +++ b/includes/silcincludes.h.in @@ -231,6 +231,7 @@ extern "C" { #include "silchmac.h" #include "silcrng.h" #include "silcpkcs.h" +#include "silcpkcs1.h" /* More SILC util library includes */ #include "silcmutex.h" diff --git a/lib/silccrypt/DIRECTORY b/lib/silccrypt/DIRECTORY index c585952f..6c7c7432 100644 --- a/lib/silccrypt/DIRECTORY +++ b/lib/silccrypt/DIRECTORY @@ -5,6 +5,7 @@ @LINK=silcrng.html:SILC RNG Interface @LINK=silccipher.html:SILC Cipher API @LINK=silcpkcs.html:SILC PKCS API +@LINK=silcpkcs1.html:SILC PKCS#1 API @LINK=silchash.html:SILC Hash Interface @LINK=silchmac.html:SILC HMAC Interface --> @@ -25,4 +26,3 @@ strong random number generator.

@LINKS@ - diff --git a/lib/silccrypt/Makefile.am b/lib/silccrypt/Makefile.am index d3e6e842..87d56138 100644 --- a/lib/silccrypt/Makefile.am +++ b/lib/silccrypt/Makefile.am @@ -1,14 +1,13 @@ # # Makefile.am # -# Author: Pekka Riikonen +# Author: Pekka Riikonen # -# Copyright (C) 2000 Pekka Riikonen +# Copyright (C) 2000 2003 Pekka Riikonen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -35,13 +34,13 @@ libsilccrypt_la_SOURCES = \ silchmac.c \ silcrng.c \ silcpkcs.c \ - pkcs1.c + silcpkcs1.c if SILC_LIBTOOLFIX # Tell libtool to compile silccrypt as shared since silcsim will need it. LTFLAGS = --libtool-enable-shared else -LTFLAGS = +LTFLAGS = endif CFLAGS = $(LTFLAGS) @@ -55,7 +54,6 @@ include_HEADERS = \ ciphers.h \ md5.h \ none.h \ - pkcs1.h \ rc5.h \ rsa.h \ sha1.h \ @@ -65,6 +63,7 @@ include_HEADERS = \ silchmac.h \ silcpkcs.h \ silcrng.h \ + silcpkcs1.h \ twofish.h endif diff --git a/lib/silccrypt/pkcs1.c b/lib/silccrypt/pkcs1.c deleted file mode 100644 index a357be44..00000000 --- a/lib/silccrypt/pkcs1.c +++ /dev/null @@ -1,475 +0,0 @@ -/* $Id$ */ -/* - PKCS #1 RSA wrapper. - - Heavily modified to work under SILC, rewrote all interfaces, code that - is not needed in SILC has been removed for good, and some code was fixed - and changed. - - For example, RSA_DecodeOneBlock was not used at all by Mozilla, however, - I took this code in to use after doing some fixing (it had some bugs). - Also, OAEP is removed totally for now. I'm not sure whether OAEP could - be used in the future with SILC but not for now. - - This file also implements partial SILC PKCS API for RSA with PKCS #1. - It is partial because all the other functions but encrypt, decrypt, - sign and verify are common. - - Note: - - The mandatory PKCS #1 implementation in SILC must be compliant to either - PKCS #1 version 1.5 or PKCS #1 version 2 with the following notes: - The signature encoding is always in same format as the encryption - encoding regardles of the PKCS #1 version. The signature with - appendix (with hash algorithm OID in the data) must not be used - in the SILC. Rationale for this is that there is no binding between - the PKCS #1 OIDs and the hash algorithms used in the SILC protocol. - Hence, the encoding is always in PKCS #1 version 1.5 format. - - Any questions and comments regarding this modified version should be - sent to priikone@silcnet.org. - - References: ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc, - ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1.asc, - and RFC 2437. - - Copyright notice: All code in this file, including the SILC PKCS API - code that is not part of the Mozilla code, falls under the same license - (MPL or GPL) found attached to this file, below. -*/ - -/* - * PKCS#1 encoding and decoding functions. - * This file is believed to contain no code licensed from other parties. - * - * 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 compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - * - * $Id$ - */ - -#include "silcincludes.h" -#include "rsa_internal.h" -#include "rsa.h" - -#define RSA_BLOCK_MIN_PAD_LEN 8 -#define RSA_BLOCK_FIRST_OCTET 0x00 -#define RSA_BLOCK_PRIVATE0_PAD_OCTET 0x00 -#define RSA_BLOCK_PRIVATE_PAD_OCTET 0xff -#define RSA_BLOCK_AFTER_PAD_OCTET 0x00 - -/* - * RSA block types - * - * The actual values are important -- they are fixed, *not* arbitrary. - * The explicit value assignments are not needed (because C would give - * us those same values anyway) but are included as a reminder... - */ -typedef enum { - RSA_BlockPrivate0 = 0, /* unused, really */ - RSA_BlockPrivate = 1, /* pad for a private-key operation */ - RSA_BlockPublic = 2, /* pad for a public-key operation */ - RSA_BlockTotal -} RSA_BlockType; - -/* - * Format one block of data for public/private key encryption using - * the rules defined in PKCS #1. - */ -static unsigned char * -RSA_FormatOneBlock(SilcUInt32 modulusLen, RSA_BlockType blockType, - unsigned char *data, SilcUInt32 data_len) -{ - unsigned char *block; - unsigned char *bp; - int padLen; - int i; - - block = (unsigned char *) silc_malloc(modulusLen); - if (block == NULL) - return NULL; - - bp = block; - - /* - * All RSA blocks start with two octets: - * 0x00 || BlockType - */ - *bp++ = RSA_BLOCK_FIRST_OCTET; - *bp++ = (unsigned char) blockType; - - switch (blockType) { - - /* - * Blocks intended for private-key operation. - */ - case RSA_BlockPrivate0: /* essentially unused */ - case RSA_BlockPrivate: /* preferred method */ - /* - * 0x00 || BT || Pad || 0x00 || ActualData - * 1 1 padLen 1 data_len - * Pad is either all 0x00 or all 0xff bytes, depending on blockType. - */ - padLen = modulusLen - data_len - 3; - assert(padLen >= RSA_BLOCK_MIN_PAD_LEN); - memset(bp, - blockType == RSA_BlockPrivate0 - ? RSA_BLOCK_PRIVATE0_PAD_OCTET - : RSA_BLOCK_PRIVATE_PAD_OCTET, - padLen); - bp += padLen; - *bp++ = RSA_BLOCK_AFTER_PAD_OCTET; - memcpy(bp, data, data_len); - break; - - /* - * Blocks intended for public-key operation. - */ - case RSA_BlockPublic: - /* - * 0x00 || BT || Pad || 0x00 || ActualData - * 1 1 padLen 1 data_len - * Pad is all non-zero random bytes. - */ - padLen = modulusLen - data_len - 3; - assert(padLen >= RSA_BLOCK_MIN_PAD_LEN); - for (i = 0; i < padLen; i++) { - /* Pad with non-zero random data. */ - do { - bp[i] = silc_rng_global_get_byte(); - } while (bp[i] == RSA_BLOCK_AFTER_PAD_OCTET); - } - bp += padLen; - *bp++ = RSA_BLOCK_AFTER_PAD_OCTET; - memcpy(bp, data, data_len); - break; - - default: - silc_free(block); - return NULL; - } - - return block; -} - -static int -RSA_FormatBlock(unsigned char **result, SilcUInt32 *result_len, - SilcUInt32 modulusLen, - RSA_BlockType blockType, unsigned char *data, - SilcUInt32 data_len) -{ - /* - * XXX For now assume that the data length fits in a single - * XXX encryption block; the ASSERTs below force this. - * XXX To fix it, each case will have to loop over chunks whose - * XXX lengths satisfy the assertions, until all data is handled. - * XXX (Unless RSA has more to say about how to handle data - * XXX which does not fit in a single encryption block?) - * XXX And I do not know what the result is supposed to be, - * XXX so the interface to this function may need to change - * XXX to allow for returning multiple blocks, if they are - * XXX not wanted simply concatenated one after the other. - */ - - switch (blockType) { - case RSA_BlockPrivate0: - case RSA_BlockPrivate: - case RSA_BlockPublic: - /* - * 0x00 || BT || Pad || 0x00 || ActualData - * - * The "3" below is the first octet + the second octet + the 0x00 - * octet that always comes just before the ActualData. - */ - assert(data_len <= (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN))); - - *result = RSA_FormatOneBlock(modulusLen, blockType, data, data_len); - if (result == NULL) { - *result_len = 0; - return FALSE; - } - *result_len = modulusLen; - - break; - - default: - *result = NULL; - *result_len = 0; - return FALSE; - } - - return TRUE; -} - -/* - * Takes a formatted block and returns the data part. - * (This is the inverse of RSA_FormatOneBlock().) - * In some formats the start of the data is ambiguous; - * if it is non-zero, expectedLen will disambiguate. - * - */ -unsigned char * -RSA_DecodeOneBlock(unsigned char *data, - SilcUInt32 modulusLen, - SilcUInt32 expectedLen, - RSA_BlockType bt, - SilcUInt32 *pResultLen) -{ - RSA_BlockType blockType; - unsigned char *dp, *res; - SilcUInt32 i, len = 0; - - dp = data; - if (dp[0] != RSA_BLOCK_FIRST_OCTET) { - return NULL; - } - - blockType = (RSA_BlockType)dp[1]; - if (blockType != bt) - return NULL; - - if (modulusLen < 2 + 1) - return NULL; - - dp += 2; - - switch (blockType) { - case RSA_BlockPrivate0: - /* Ignored */ - res = (unsigned char *) silc_malloc(modulusLen); - memcpy(res, data, modulusLen); - break; - - case RSA_BlockPrivate: - for (i = 0; i < modulusLen; i++) { - if (*dp++ != RSA_BLOCK_PRIVATE_PAD_OCTET) - break; - } - if (i == modulusLen) - return NULL; - len = modulusLen - (dp - data); - res = (unsigned char *) silc_malloc(len); - if (res == NULL) { - return NULL; - } - memcpy(res, dp, len); - break; - - case RSA_BlockPublic: - for (i = 0; i < modulusLen; i++) { - if (*dp++ == RSA_BLOCK_AFTER_PAD_OCTET) - break; - } - if (i == modulusLen) - return NULL; - len = modulusLen - (dp - data); - res = (unsigned char *) silc_malloc(len); - if (res == NULL) { - return NULL; - } - memcpy(res, dp, len); - break; - - default: - return NULL; - } - - if (pResultLen) - *pResultLen = len; - return res; -} - -/* - * SILC PKCS API for PKCS #1 - * - * Note all the other PKCS API functions are used from the rsa.c. - * See the definitions in rsa.c and in silcpkcs.c. - */ - -SILC_PKCS_API_ENCRYPT(pkcs1) -{ - RsaKey *key = (RsaKey *)context; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - unsigned char *padded; - SilcUInt32 padded_len, len = (key->bits + 7) / 8; - - /* Pad data */ - if (!RSA_FormatBlock(&padded, &padded_len, len, - RSA_BlockPublic, src, src_len)) - return FALSE; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Data to MP */ - silc_mp_bin2mp(padded, padded_len, &mp_tmp); - - /* Encrypt */ - rsa_public_operation(key, &mp_tmp, &mp_dst); - - /* MP to data */ - silc_mp_mp2bin_noalloc(&mp_dst, dst, len); - *dst_len = len; - - memset(padded, 0, padded_len); - silc_free(padded); - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_DECRYPT(pkcs1) -{ - RsaKey *key = (RsaKey *)context; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - unsigned char *padded, *unpadded; - SilcUInt32 padded_len; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Data to MP */ - silc_mp_bin2mp(src, src_len, &mp_tmp); - - /* Decrypt */ - rsa_private_operation(key, &mp_tmp, &mp_dst); - - /* MP to data */ - padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len); - - /* Unpad data */ - unpadded = RSA_DecodeOneBlock(padded, padded_len, 0, - RSA_BlockPublic, &padded_len); - if (!unpadded) { - memset(padded, 0, padded_len); - silc_free(padded); - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - return FALSE; - } - - /* Copy to destination */ - memcpy(dst, unpadded, padded_len); - *dst_len = padded_len; - - memset(padded, 0, padded_len); - memset(unpadded, 0, padded_len); - silc_free(padded); - silc_free(unpadded); - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_SIGN(pkcs1) -{ - RsaKey *key = (RsaKey *)context; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - unsigned char *padded; - SilcUInt32 padded_len; - SilcUInt32 len = (key->bits + 7) / 8; - - /* Pad data */ - if (!RSA_FormatBlock(&padded, &padded_len, len, RSA_BlockPrivate, - src, src_len)) - return FALSE; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Data to MP */ - silc_mp_bin2mp(padded, len, &mp_tmp); - - /* Sign */ - rsa_private_operation(key, &mp_tmp, &mp_dst); - - /* MP to data */ - silc_mp_mp2bin_noalloc(&mp_dst, dst, len); - *dst_len = len; - - memset(padded, 0, padded_len); - silc_free(padded); - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_VERIFY(pkcs1) -{ - RsaKey *key = (RsaKey *)context; - int ret = TRUE; - SilcMPInt mp_tmp2; - SilcMPInt mp_dst; - unsigned char *verify, *unpadded; - SilcUInt32 verify_len, len = (key->bits + 7) / 8; - - silc_mp_init(&mp_tmp2); - silc_mp_init(&mp_dst); - - /* Format the signature into MP int */ - silc_mp_bin2mp(signature, signature_len, &mp_tmp2); - - /* Verify */ - rsa_public_operation(key, &mp_tmp2, &mp_dst); - - /* MP to data */ - verify = silc_mp_mp2bin(&mp_dst, len, &verify_len); - - /* Unpad data */ - unpadded = RSA_DecodeOneBlock(verify, len, 0, - RSA_BlockPrivate, &verify_len); - if (!unpadded) { - memset(verify, 0, verify_len); - silc_free(verify); - silc_mp_uninit(&mp_tmp2); - silc_mp_uninit(&mp_dst); - return FALSE; - } - - /* Compare */ - if (memcmp(data, unpadded, verify_len)) - ret = FALSE; - - memset(verify, 0, verify_len); - memset(unpadded, 0, verify_len); - silc_free(verify); - silc_free(unpadded); - silc_mp_uninit(&mp_tmp2); - silc_mp_uninit(&mp_dst); - - return ret; -} diff --git a/lib/silccrypt/pkcs1.h b/lib/silccrypt/pkcs1.h deleted file mode 100644 index 38937aee..00000000 --- a/lib/silccrypt/pkcs1.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - - pkcs1.h - - Author: Pekka Riikonen - - Copyright (C) 2001 Pekka Riikonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - -*/ -#ifndef PKCS1_H -#define PKCS1_H - -/* - * SILC PKCS API for PKCS #1 - * - * Note all the other PKCS API functions are used from the rsa.c. - * See the definitions in rsa.c and in silcpkcs.c. - */ - -SILC_PKCS_API_ENCRYPT(pkcs1); -SILC_PKCS_API_DECRYPT(pkcs1); -SILC_PKCS_API_SIGN(pkcs1); -SILC_PKCS_API_VERIFY(pkcs1); - -#endif diff --git a/lib/silccrypt/rsa.c b/lib/silccrypt/rsa.c index ceab6edb..7f9beb17 100644 --- a/lib/silccrypt/rsa.c +++ b/lib/silccrypt/rsa.c @@ -483,6 +483,8 @@ SILC_PKCS_API_CONTEXT_LEN(rsa) return sizeof(RsaKey); } +/* Raw RSA routines */ + SILC_PKCS_API_ENCRYPT(rsa) { RsaKey *key = (RsaKey *)context; @@ -600,6 +602,167 @@ SILC_PKCS_API_VERIFY(rsa) return ret; } + +/* PKCS#1 RSA routines */ + +SILC_PKCS_API_ENCRYPT(pkcs1) +{ + RsaKey *key = (RsaKey *)context; + SilcMPInt mp_tmp; + SilcMPInt mp_dst; + unsigned char padded[2048 + 1]; + SilcUInt32 len = (key->bits + 7) / 8; + + if (sizeof(padded) < len) + return FALSE; + + /* Pad data */ + if (!silc_pkcs1_encode(SILC_PKCS1_BT_PUB, src, src_len, + padded, len, NULL)) + return FALSE; + + silc_mp_init(&mp_tmp); + silc_mp_init(&mp_dst); + + /* Data to MP */ + silc_mp_bin2mp(padded, len, &mp_tmp); + + /* Encrypt */ + rsa_public_operation(key, &mp_tmp, &mp_dst); + + /* MP to data */ + silc_mp_mp2bin_noalloc(&mp_dst, dst, len); + *dst_len = len; + + memset(padded, 0, sizeof(padded)); + silc_mp_uninit(&mp_tmp); + silc_mp_uninit(&mp_dst); + + return TRUE; +} + +SILC_PKCS_API_DECRYPT(pkcs1) +{ + RsaKey *key = (RsaKey *)context; + SilcMPInt mp_tmp; + SilcMPInt mp_dst; + unsigned char *padded, unpadded[2048 + 1]; + SilcUInt32 padded_len; + + silc_mp_init(&mp_tmp); + silc_mp_init(&mp_dst); + + /* Data to MP */ + silc_mp_bin2mp(src, src_len, &mp_tmp); + + /* Decrypt */ + rsa_private_operation(key, &mp_tmp, &mp_dst); + + /* MP to data */ + padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len); + + /* Unpad data */ + if (!silc_pkcs1_decode(SILC_PKCS1_BT_PUB, padded, padded_len, + unpadded, sizeof(unpadded), dst_len)) { + memset(padded, 0, padded_len); + silc_free(padded); + silc_mp_uninit(&mp_tmp); + silc_mp_uninit(&mp_dst); + return FALSE; + } + + /* Copy to destination */ + memcpy(dst, unpadded, *dst_len); + + memset(padded, 0, padded_len); + memset(unpadded, 0, sizeof(unpadded)); + silc_free(padded); + silc_mp_uninit(&mp_tmp); + silc_mp_uninit(&mp_dst); + + return TRUE; +} + +SILC_PKCS_API_SIGN(pkcs1) +{ + RsaKey *key = (RsaKey *)context; + SilcMPInt mp_tmp; + SilcMPInt mp_dst; + unsigned char padded[2048 + 1]; + SilcUInt32 len = (key->bits + 7) / 8; + + if (sizeof(padded) < len) + return FALSE; + + /* Pad data */ + if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len, + padded, len, NULL)) + return FALSE; + + silc_mp_init(&mp_tmp); + silc_mp_init(&mp_dst); + + /* Data to MP */ + silc_mp_bin2mp(padded, len, &mp_tmp); + + /* Sign */ + rsa_private_operation(key, &mp_tmp, &mp_dst); + + /* MP to data */ + silc_mp_mp2bin_noalloc(&mp_dst, dst, len); + *dst_len = len; + + memset(padded, 0, sizeof(padded)); + silc_mp_uninit(&mp_tmp); + silc_mp_uninit(&mp_dst); + + return TRUE; +} + +SILC_PKCS_API_VERIFY(pkcs1) +{ + RsaKey *key = (RsaKey *)context; + int ret = TRUE; + SilcMPInt mp_tmp2; + SilcMPInt mp_dst; + unsigned char *verify, unpadded[2048 + 1]; + SilcUInt32 verify_len, len = (key->bits + 7) / 8; + + silc_mp_init(&mp_tmp2); + silc_mp_init(&mp_dst); + + /* Format the signature into MP int */ + silc_mp_bin2mp(signature, signature_len, &mp_tmp2); + + /* Verify */ + rsa_public_operation(key, &mp_tmp2, &mp_dst); + + /* MP to data */ + verify = silc_mp_mp2bin(&mp_dst, len, &verify_len); + + /* Unpad data */ + if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len, + unpadded, sizeof(unpadded), &len)) { + memset(verify, 0, verify_len); + silc_free(verify); + silc_mp_uninit(&mp_tmp2); + silc_mp_uninit(&mp_dst); + return FALSE; + } + + /* Compare */ + if (memcmp(data, unpadded, len)) + ret = FALSE; + + memset(verify, 0, verify_len); + memset(unpadded, 0, sizeof(unpadded)); + silc_free(verify); + silc_mp_uninit(&mp_tmp2); + silc_mp_uninit(&mp_dst); + + return ret; +} + /* Generates RSA public and private keys. Primes p and q that are used to compute the modulus n has to be generated before calling this. They are then sent as argument for the function. */ diff --git a/lib/silccrypt/rsa.h b/lib/silccrypt/rsa.h index 5f8262fa..a697fef4 100644 --- a/lib/silccrypt/rsa.h +++ b/lib/silccrypt/rsa.h @@ -2,15 +2,14 @@ rsa.h - Author: Pekka Riikonen + Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + Copyright (C) 1997 - 2003 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -37,5 +36,10 @@ SILC_PKCS_API_DECRYPT(rsa); SILC_PKCS_API_SIGN(rsa); SILC_PKCS_API_VERIFY(rsa); +SILC_PKCS_API_ENCRYPT(pkcs1); +SILC_PKCS_API_DECRYPT(pkcs1); +SILC_PKCS_API_SIGN(pkcs1); +SILC_PKCS_API_VERIFY(pkcs1); + #endif diff --git a/lib/silccrypt/silcpkcs.c b/lib/silccrypt/silcpkcs.c index 21bab68e..6ce2f9fa 100644 --- a/lib/silccrypt/silcpkcs.c +++ b/lib/silccrypt/silcpkcs.c @@ -21,7 +21,6 @@ #include "silcincludes.h" #include "rsa.h" -#include "pkcs1.h" /* The main SILC PKCS structure. */ struct SilcPKCSStruct { diff --git a/lib/silccrypt/silcpkcs1.c b/lib/silccrypt/silcpkcs1.c new file mode 100644 index 00000000..769c8d50 --- /dev/null +++ b/lib/silccrypt/silcpkcs1.c @@ -0,0 +1,149 @@ +/* + + silcpkcs1.c + + Author: Pekka Riikonen + + Copyright (C) 2003 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#include "silcincludes.h" +#include "silcpkcs1.h" + +/* Encodes PKCS#1 data block from the `data' according to the block type + indicated by `bt'. When encoding signatures the `bt' must be + SILC_PKCS1_BT_PRV1 and when encoding encryption blocks the `bt' must + be SILC_PKCS1_BT_PUB. The encoded data is copied into the `dest_data' + buffer which is size of `dest_data_size'. If the `dest_data' is not + able to hold the encoded block this returns FALSE. The `rng' must be + set when `bt' is SILC_PKCS1_BT_PUB. This function returns TRUE on + success. */ + +bool silc_pkcs1_encode(SilcPkcs1BlockType bt, + const unsigned char *data, + SilcUInt32 data_len, + unsigned char *dest_data, + SilcUInt32 dest_data_size, + SilcRng rng) +{ + SilcInt32 padlen; + int i; + + SILC_LOG_DEBUG(("PKCS#1 encoding, bt %d", bt)); + + if (!data || !dest_data || + dest_data_size < 3 || dest_data_size < data_len) { + SILC_LOG_DEBUG(("Data to be encoded is too long")); + return FALSE; + } + + /* Start of block */ + dest_data[0] = 0x00; + dest_data[1] = (unsigned char)bt; + + padlen = (SilcInt32)dest_data_size - (SilcInt32)data_len - 3; + if (padlen < 8) { + SILC_LOG_DEBUG(("Data to be encoded is too long")); + return FALSE; + } + + /* Encode according to block type */ + switch (bt) { + case SILC_PKCS1_BT_PRV0: + case SILC_PKCS1_BT_PRV1: + /* Signature */ + memset(dest_data + 2, bt == SILC_PKCS1_BT_PRV1 ? 0xff : 0x00, padlen); + break; + + case SILC_PKCS1_BT_PUB: + /* Encryption */ + for (i = 2; i < padlen; i++) { + /* It is guaranteed this routine does not return zero byte. */ + if (rng) + dest_data[i] = silc_rng_get_byte_fast(rng); + else + dest_data[i] = silc_rng_global_get_byte_fast(); + } + + break; + } + + /* Copy the data */ + dest_data[padlen + 2] = 0x00; + memcpy(dest_data + padlen + 3, data, data_len); + + return TRUE; +} + +/* Decodes the PKCS#1 encoded block according to the block type `bt'. + When verifying signatures the `bt' must be SILC_PKCS1_BT_PRV1 and + when decrypting it must be SILC_PKCS1_BT_PUB. This copies the + decoded data into `dest_data' which is size of `dest_data_size'. If + the deocded block does not fit to `dest_data' this returns FALSE. + Returns TRUE on success. */ + +bool silc_pkcs1_decode(SilcPkcs1BlockType bt, + const unsigned char *data, + SilcUInt32 data_len, + unsigned char *dest_data, + SilcUInt32 dest_data_size, + SilcUInt32 *dest_len) +{ + int i = 0; + + SILC_LOG_DEBUG(("PKCS#1 decoding, bt %d", bt)); + + /* Sanity checks */ + if (!data || !dest_data || dest_data_size < 3 || + data[0] != 0x00 || data[1] != (unsigned char)bt) { + SILC_LOG_DEBUG(("Malformed block")); + return FALSE; + } + + /* Decode according to block type */ + switch (bt) { + case SILC_PKCS1_BT_PRV0: + /* Do nothing */ + break; + + case SILC_PKCS1_BT_PRV1: + /* Verification */ + for (i = 2; i < data_len; i++) + if (data[i] != 0xff) + break; + break; + + case SILC_PKCS1_BT_PUB: + /* Decryption */ + for (i = 2; i < data_len; i++) + if (data[i] == 0x00) + break; + break; + } + + /* Sanity checks */ + if (data[i] != 0x00 || i < 10 - 2) + return FALSE; + i++; + if (dest_data_size < data_len - i) + return FALSE; + + /* Copy the data */ + memcpy(dest_data, data + i, data_len - i); + + /* Return data length */ + if (dest_len) + *dest_len = data_len - i; + + return TRUE; +} diff --git a/lib/silccrypt/silcpkcs1.h b/lib/silccrypt/silcpkcs1.h new file mode 100644 index 00000000..573777c1 --- /dev/null +++ b/lib/silccrypt/silcpkcs1.h @@ -0,0 +1,115 @@ +/* + + silcpkcs1.h + + Author: Pekka Riikonen + + Copyright (C) 2003 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +/****h* silccrypt/SILC PKCS1 Interface + * + * DESCRIPTION + * + * This interface implements the PKCS#1 standard block encoding and decoding + * routines. It is used as part of RSA implementation to perform PKCS#1 + * RSA operations. The routines encode and decode the data for RSA operations + * such as digital signatures and their verification, and encryption and + * decryption. + * + ***/ + +#ifndef SILCPKCS1_H +#define SILCPKCS1_H + +/****d* silccrypt/SilcPKCS1API/SilcPkcs1BlockType + * + * NAME + * + * typedef enum { ... } SilcPkcs1BlockType + * + * DESCRIPTION + * + * Defines the PKCS#1 block types that define how the blcok is encoded + * for different RSA operations. + * + * SOURCE + */ +typedef enum { + SILC_PKCS1_BT_PRV0 = 0x00, /* Private key BT 0 */ + SILC_PKCS1_BT_PRV1 = 0x01, /* Private key BT 1 (use this always) */ + SILC_PKCS1_BT_PUB = 0x02, /* Public key BT */ +} SilcPkcs1BlockType; +/***/ + +/****f* silccrypt/SilcPKCS1API/silc_pkcs1_encode + * + * SYNOPSIS + * + * bool silc_pkcs1_encode(SilcPkcs1BlockType bt, + * const unsigned char *data, + * SilcUInt32 data_len, + * unsigned char *dest_data, + * SilcUInt32 dest_data_size, + * SilcRng rng); + * + * DESCRIPTION + * + * Encodes PKCS#1 data block from the `data' according to the block type + * indicated by `bt'. When encoding signatures the `bt' must be + * SILC_PKCS1_BT_PRV1 and when encoding encryption blocks the `bt' must + * be SILC_PKCS1_BT_PUB. The encoded data is copied into the `dest_data' + * buffer which is size of `dest_data_size'. If the `dest_data' is not + * able to hold the encoded block this returns FALSE. Usually the + * `dest_data_size' is set to the RSA key length value as it is the + * length of one block. The `rng' should be set when `bt' is set to + * SILC_PKCS1_BT_PUB. If `rng' is NULL global RNG is used. This + * function returns TRUE on success. + * + ***/ +bool silc_pkcs1_encode(SilcPkcs1BlockType bt, + const unsigned char *data, + SilcUInt32 data_len, + unsigned char *dest_data, + SilcUInt32 dest_data_size, + SilcRng rng); + +/****f* silccrypt/SilcPKCS1API/silc_pkcs1_decode + * + * SYNOPSIS + * + * bool silc_pkcs1_decode(SilcPkcs1BlockType bt, + * const unsigned char *data, + * SilcUInt32 data_len, + * unsigned char *dest_data, + * SilcUInt32 dest_data_size, + * SilcUInt32 *dest_len); + * + * DESCRIPTION + * + * Decodes the PKCS#1 encoded block according to the block type `bt'. + * When verifying signatures the `bt' must be SILC_PKCS1_BT_PRV1 and + * when decrypting it must be SILC_PKCS1_BT_PUB. This copies the + * decoded data into `dest_data' which is size of `dest_data_size'. If + * the deocded block does not fit to `dest_data' this returns FALSE. + * Returns the decoded length into `dest_len'. + * + ***/ +bool silc_pkcs1_decode(SilcPkcs1BlockType bt, + const unsigned char *data, + SilcUInt32 data_len, + unsigned char *dest_data, + SilcUInt32 dest_data_size, + SilcUInt32 *dest_len); + +#endif /* SILCPKCS1_H */ -- 2.43.0