mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
91adebe749
Andrew Bartlett
(This used to be commit ae0f81ab23
)
446 lines
9.2 KiB
C
446 lines
9.2 KiB
C
/*
|
|
* Copyright (c) 2006 Kungliga Tekniska Högskolan
|
|
* (Royal Institute of Technology, Stockholm, Sweden).
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. 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.
|
|
*
|
|
* 3. Neither the name of the Institute nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
RCSID("$Id: bn.c 18449 2006-10-14 09:21:09Z lha $");
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#include <krb5-types.h>
|
|
#include <rfc2459_asn1.h> /* XXX */
|
|
#include <der.h>
|
|
|
|
#include <bn.h>
|
|
#include <rand.h>
|
|
#include <hex.h>
|
|
|
|
BIGNUM *
|
|
BN_new(void)
|
|
{
|
|
heim_integer *hi;
|
|
hi = calloc(1, sizeof(*hi));
|
|
return (BIGNUM *)hi;
|
|
}
|
|
|
|
void
|
|
BN_free(BIGNUM *bn)
|
|
{
|
|
BN_clear(bn);
|
|
free(bn);
|
|
}
|
|
|
|
void
|
|
BN_clear(BIGNUM *bn)
|
|
{
|
|
heim_integer *hi = (heim_integer *)bn;
|
|
if (hi->data) {
|
|
memset(hi->data, 0, hi->length);
|
|
free(hi->data);
|
|
}
|
|
memset(hi, 0, sizeof(*hi));
|
|
}
|
|
|
|
void
|
|
BN_clear_free(BIGNUM *bn)
|
|
{
|
|
BN_free(bn);
|
|
}
|
|
|
|
BIGNUM *
|
|
BN_dup(const BIGNUM *bn)
|
|
{
|
|
BIGNUM *b = BN_new();
|
|
if (der_copy_heim_integer((const heim_integer *)bn, (heim_integer *)b)) {
|
|
BN_free(b);
|
|
return NULL;
|
|
}
|
|
return b;
|
|
}
|
|
|
|
/*
|
|
* If the caller really want to know the number of bits used, subtract
|
|
* one from the length, multiply by 8, and then lookup in the table
|
|
* how many bits the hightest byte uses.
|
|
*/
|
|
int
|
|
BN_num_bits(const BIGNUM *bn)
|
|
{
|
|
static unsigned char num2bits[256] = {
|
|
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
|
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
|
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
|
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
|
};
|
|
const heim_integer *i = (const void *)bn;
|
|
if (i->length == 0)
|
|
return 0;
|
|
return (i->length - 1) * 8 + num2bits[((unsigned char *)i->data)[0]];
|
|
}
|
|
|
|
int
|
|
BN_num_bytes(const BIGNUM *bn)
|
|
{
|
|
return ((const heim_integer *)bn)->length;
|
|
}
|
|
|
|
/*
|
|
* Ignore negative flag.
|
|
*/
|
|
|
|
BIGNUM *
|
|
BN_bin2bn(const void *s, int len, BIGNUM *bn)
|
|
{
|
|
heim_integer *hi = (void *)bn;
|
|
|
|
if (len < 0)
|
|
return NULL;
|
|
|
|
if (hi == NULL) {
|
|
hi = (heim_integer *)BN_new();
|
|
if (hi == NULL)
|
|
return NULL;
|
|
}
|
|
if (hi->data)
|
|
BN_clear((BIGNUM *)hi);
|
|
hi->negative = 0;
|
|
hi->data = malloc(len);
|
|
if (hi->data == NULL && len != 0) {
|
|
if (bn == NULL)
|
|
BN_free((BIGNUM *)hi);
|
|
return NULL;
|
|
}
|
|
hi->length = len;
|
|
memcpy(hi->data, s, len);
|
|
return (BIGNUM *)hi;
|
|
}
|
|
|
|
int
|
|
BN_bn2bin(const BIGNUM *bn, void *to)
|
|
{
|
|
const heim_integer *hi = (const void *)bn;
|
|
memcpy(to, hi->data, hi->length);
|
|
return hi->length;
|
|
}
|
|
|
|
int
|
|
BN_hex2bn(BIGNUM **bnp, const char *in)
|
|
{
|
|
int negative;
|
|
ssize_t ret;
|
|
size_t len;
|
|
void *data;
|
|
|
|
len = strlen(in);
|
|
data = malloc(len);
|
|
if (data == NULL)
|
|
return 0;
|
|
|
|
if (*in == '-') {
|
|
negative = 1;
|
|
in++;
|
|
} else
|
|
negative = 0;
|
|
|
|
ret = hex_decode(in, data, len);
|
|
if (ret < 0) {
|
|
free(data);
|
|
return 0;
|
|
}
|
|
|
|
*bnp = BN_bin2bn(data, ret, NULL);
|
|
free(data);
|
|
if (*bnp == NULL)
|
|
return 0;
|
|
BN_set_negative(*bnp, negative);
|
|
return 1;
|
|
}
|
|
|
|
char *
|
|
BN_bn2hex(const BIGNUM *bn)
|
|
{
|
|
ssize_t ret;
|
|
size_t len;
|
|
void *data;
|
|
char *str;
|
|
|
|
len = BN_num_bytes(bn);
|
|
data = malloc(len);
|
|
if (data == NULL)
|
|
return 0;
|
|
|
|
len = BN_bn2bin(bn, data);
|
|
|
|
ret = hex_encode(data, len, &str);
|
|
free(data);
|
|
if (ret < 0)
|
|
return 0;
|
|
|
|
return str;
|
|
}
|
|
|
|
int
|
|
BN_cmp(const BIGNUM *bn1, const BIGNUM *bn2)
|
|
{
|
|
return der_heim_integer_cmp((const heim_integer *)bn1,
|
|
(const heim_integer *)bn2);
|
|
}
|
|
|
|
void
|
|
BN_set_negative(BIGNUM *bn, int flag)
|
|
{
|
|
((heim_integer *)bn)->negative = (flag ? 1 : 0);
|
|
}
|
|
|
|
int
|
|
BN_is_negative(BIGNUM *bn)
|
|
{
|
|
return ((heim_integer *)bn)->negative ? 1 : 0;
|
|
}
|
|
|
|
static const unsigned char is_set[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
|
|
|
|
int
|
|
BN_is_bit_set(const BIGNUM *bn, int bit)
|
|
{
|
|
heim_integer *hi = (heim_integer *)bn;
|
|
unsigned char *p = hi->data;
|
|
|
|
if ((bit / 8) > hi->length || hi->length == 0)
|
|
return 0;
|
|
|
|
return p[hi->length - 1 - (bit / 8)] & is_set[bit % 8];
|
|
}
|
|
|
|
int
|
|
BN_set_bit(BIGNUM *bn, int bit)
|
|
{
|
|
heim_integer *hi = (heim_integer *)bn;
|
|
unsigned char *p;
|
|
|
|
if ((bit / 8) > hi->length || hi->length == 0) {
|
|
size_t len = (bit + 7) / 8;
|
|
void *d = realloc(hi->data, len);
|
|
if (d == NULL)
|
|
return 0;
|
|
hi->data = d;
|
|
p = hi->data;
|
|
memset(&p[hi->length], 0, len);
|
|
hi->length = len;
|
|
} else
|
|
p = hi->data;
|
|
|
|
p[hi->length - 1 - (bit / 8)] |= is_set[bit % 8];
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
BN_clear_bit(BIGNUM *bn, int bit)
|
|
{
|
|
heim_integer *hi = (heim_integer *)bn;
|
|
unsigned char *p = hi->data;
|
|
|
|
if ((bit / 8) > hi->length || hi->length == 0)
|
|
return 0;
|
|
|
|
p[hi->length - 1 - (bit / 8)] &= (unsigned char)(~(is_set[bit % 8]));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
BN_set_word(BIGNUM *bn, unsigned long num)
|
|
{
|
|
unsigned char p[sizeof(num)];
|
|
unsigned long num2;
|
|
int i, len;
|
|
|
|
for (num2 = num, i = 0; num2 > 0; i++)
|
|
num2 = num2 >> 8;
|
|
|
|
len = i - 1;
|
|
for (; i > 0; i--) {
|
|
p[i - 1] = (num & 0xff);
|
|
num = num >> 8;
|
|
}
|
|
|
|
bn = BN_bin2bn(p, len + 1, bn);
|
|
return bn != NULL;
|
|
}
|
|
|
|
unsigned long
|
|
BN_get_word(const BIGNUM *bn)
|
|
{
|
|
heim_integer *hi = (heim_integer *)bn;
|
|
unsigned long num = 0;
|
|
int i;
|
|
|
|
if (hi->negative || hi->length > sizeof(num))
|
|
return ULONG_MAX;
|
|
|
|
for (i = 0; i < hi->length; i++)
|
|
num = ((unsigned char *)hi->data)[i] | (num << 8);
|
|
return num;
|
|
}
|
|
|
|
int
|
|
BN_rand(BIGNUM *bn, int bits, int top, int bottom)
|
|
{
|
|
size_t len = (bits + 7) / 8;
|
|
heim_integer *i = (heim_integer *)bn;
|
|
|
|
BN_clear(bn);
|
|
|
|
i->negative = 0;
|
|
i->data = malloc(len);
|
|
if (i->data == NULL && len != 0)
|
|
return 0;
|
|
i->length = len;
|
|
|
|
if (RAND_bytes(i->data, i->length) != 1) {
|
|
free(i->data);
|
|
i->data = NULL;
|
|
return 0;
|
|
}
|
|
|
|
{
|
|
size_t j = len * 8;
|
|
while(j > bits) {
|
|
BN_clear_bit(bn, j - 1);
|
|
j--;
|
|
}
|
|
}
|
|
|
|
if (top == -1) {
|
|
;
|
|
} else if (top == 0 && bits > 0) {
|
|
BN_set_bit(bn, bits - 1);
|
|
} else if (top == 1 && bits > 1) {
|
|
BN_set_bit(bn, bits - 1);
|
|
BN_set_bit(bn, bits - 2);
|
|
} else {
|
|
BN_clear(bn);
|
|
return 0;
|
|
}
|
|
|
|
if (bottom && bits > 0)
|
|
BN_set_bit(bn, 0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
|
|
int
|
|
BN_uadd(BIGNUM *res, const BIGNUM *a, const BIGNUM *b)
|
|
{
|
|
const heim_integer *ai = (const heim_integer *)a;
|
|
const heim_integer *bi = (const heim_integer *)b;
|
|
const unsigned char *ap, *bp;
|
|
unsigned char *cp;
|
|
heim_integer ci;
|
|
int carry = 0;
|
|
ssize_t len;
|
|
|
|
if (ai->negative && bi->negative)
|
|
return 0;
|
|
if (ai->length < bi->length) {
|
|
const heim_integer *si = bi;
|
|
bi = ai; ai = si;
|
|
}
|
|
|
|
ci.negative = 0;
|
|
ci.length = ai->length + 1;
|
|
ci.data = malloc(ci.length);
|
|
if (ci.data == NULL)
|
|
return 0;
|
|
|
|
ap = &((const unsigned char *)ai->data)[ai->length - 1];
|
|
bp = &((const unsigned char *)bi->data)[bi->length - 1];
|
|
cp = &((unsigned char *)ci.data)[ci.length - 1];
|
|
|
|
for (len = bi->length; len > 0; len--) {
|
|
carry = *ap + *bp + carry;
|
|
*cp = carry & 0xff;
|
|
carry = (carry & ~0xff) ? 1 : 0;
|
|
ap--; bp--; cp--;
|
|
}
|
|
for (len = ai->length - bi->length; len > 0; len--) {
|
|
carry = *ap + carry;
|
|
*cp = carry & 0xff;
|
|
carry = (carry & ~0xff) ? 1 : 0;
|
|
ap--; cp--;
|
|
}
|
|
if (!carry)
|
|
memmove(cp, cp + 1, --ci.length);
|
|
else
|
|
*cp = carry;
|
|
|
|
BN_clear(res);
|
|
*((heim_integer *)res) = ci;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Callback when doing slow generation of numbers, like primes.
|
|
*/
|
|
|
|
void
|
|
BN_GENCB_set(BN_GENCB *gencb, int (*cb_2)(int, int, BN_GENCB *), void *ctx)
|
|
{
|
|
gencb->ver = 2;
|
|
gencb->cb.cb_2 = cb_2;
|
|
gencb->arg = ctx;
|
|
}
|
|
|
|
int
|
|
BN_GENCB_call(BN_GENCB *cb, int a, int b)
|
|
{
|
|
if (cb == NULL || cb->cb.cb_2 == NULL)
|
|
return 1;
|
|
return cb->cb.cb_2(a, b, cb);
|
|
}
|