/* silcpkcs1.c Author: Pekka Riikonen Copyright (C) 2003 Pekka Riikonen The contents of this file are subject to one of the Licenses specified in the COPYING file; You may not use this file except in compliance with the License. The software distributed under the License is distributed on an "AS IS" basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the COPYING file for more information. */ /* $Id: silcpkcs1.c,v 1.1.2.3 2003/11/14 18:30:58 priikone Exp $ */ #include "silcincludes.h" #include "silcpkcs1.h" /* Minimum padding in block */ #define SILC_PKCS1_MIN_PADDING 8 /* 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 < SILC_PKCS1_MIN_PADDING) { 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 */ /* It is guaranteed this routine does not return zero byte. */ if (rng) for (i = 2; i < padlen; i++) dest_data[i] = silc_rng_get_byte_fast(rng); else for (i = 2; i < padlen; i++) 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) { SILC_LOG_DEBUG(("Malformed block")); return FALSE; } if (i - 1 < SILC_PKCS1_MIN_PADDING) { SILC_LOG_DEBUG(("Malformed block")); return FALSE; } if (dest_data_size < data_len - i) { SILC_LOG_DEBUG(("Destination buffer too small")); 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; }