Rewrote the PKCS#1 routines. Removed the Mozilla's PKCS#1 routines
authorPekka Riikonen <priikone@silcnet.org>
Mon, 10 Nov 2003 11:25:43 +0000 (11:25 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 10 Nov 2003 11:25:43 +0000 (11:25 +0000)
from SILC distributions.

CHANGES
includes/silcincludes.h.in
lib/silccrypt/DIRECTORY
lib/silccrypt/Makefile.am
lib/silccrypt/pkcs1.c [deleted file]
lib/silccrypt/pkcs1.h [deleted file]
lib/silccrypt/rsa.c
lib/silccrypt/rsa.h
lib/silccrypt/silcpkcs.c
lib/silccrypt/silcpkcs1.c [new file with mode: 0644]
lib/silccrypt/silcpkcs1.h [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 23c5cba475b61597f5e7d28f8c059d7cdee857f9..fdbf8bf3c14a20f52ec12adb6b60c86389357ef7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,11 @@
-Sun Nov  9 20:44:56 EET 200  Pekka Riikonen <priikone@silcnet.org>
+Mon Nov 10 13:03:46 EET 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * 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 <priikone@silcnet.org>
 
        * Fixed nickname formatting when changing only case of the
          nickname.  Affected file lib/silcclient/idlist.c.
index 65bf8bdbcf80846fa2017fbf68e8af836dc7c9ab..0d923e4508c658201ca40d546953dd571c752ca7 100644 (file)
@@ -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"
index c585952f75d23af04ebdc741f59953a020c5d048..6c7c743205336bde1cca4d360c05a4cd09279e64 100644 (file)
@@ -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.
 
 <br /><br />
 @LINKS@
-
index d3e6e8426de05fbf7d851a0a8904e82d9c084acb..87d5613848f7bf6c8dac6ec0e440ba9cd6a2d3cb 100644 (file)
@@ -1,14 +1,13 @@
 #
 #  Makefile.am
 #
-#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#  Author: Pekka Riikonen <priikone@silcnet.org>
 #
-#  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 (file)
index a357be4..0000000
+++ /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 (file)
index 38937ae..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-
-  pkcs1.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  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
index ceab6edb8cdda8849e8f21ff22c2ff9bb65ced6f..7f9beb17d727d02cd835bbfeb7e90474b75c908b 100644 (file)
@@ -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. */
index 5f8262fa80f85c7194c6c8bec9b2c1b3c9e060b9..a697fef493a8c6d51bddfc33d221e5964a6c9d11 100644 (file)
@@ -2,15 +2,14 @@
 
   rsa.h
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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
index 21bab68e9ab5f40844c3acfefade14d1a1893e15..6ce2f9fa389670e4c9991ee72267c4f418e8749a 100644 (file)
@@ -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 (file)
index 0000000..769c8d5
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+
+  silcpkcs1.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  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 (file)
index 0000000..573777c
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+
+  silcpkcs1.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  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 */