1 /*	$NetBSD: n-fold.c,v 1.1.1.2 2014/04/24 12:45:50 pettai Exp $	*/
2 
3 /*
4  * Copyright (c) 1999 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of KTH nor the names of its contributors may be
20  *    used to endorse or promote products derived from this software without
21  *    specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
24  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
34 
35 #include "krb5_locl.h"
36 
37 static krb5_error_code
rr13(unsigned char * buf,size_t len)38 rr13(unsigned char *buf, size_t len)
39 {
40     unsigned char *tmp;
41     int bytes = (len + 7) / 8;
42     int i;
43     if(len == 0)
44 	return 0;
45     {
46 	const int bits = 13 % len;
47 	const int lbit = len % 8;
48 
49 	tmp = malloc(bytes);
50 	if (tmp == NULL)
51 	    return ENOMEM;
52 	memcpy(tmp, buf, bytes);
53 	if(lbit) {
54 	    /* pad final byte with inital bits */
55 	    tmp[bytes - 1] &= 0xff << (8 - lbit);
56 	    for(i = lbit; i < 8; i += len)
57 		tmp[bytes - 1] |= buf[0] >> i;
58 	}
59 	for(i = 0; i < bytes; i++) {
60 	    int bb;
61 	    int b1, s1, b2, s2;
62 	    /* calculate first bit position of this byte */
63 	    bb = 8 * i - bits;
64 	    while(bb < 0)
65 		bb += len;
66 	    /* byte offset and shift count */
67 	    b1 = bb / 8;
68 	    s1 = bb % 8;
69 
70 	    if(bb + 8 > bytes * 8)
71 		/* watch for wraparound */
72 		s2 = (len + 8 - s1) % 8;
73 	    else
74 		s2 = 8 - s1;
75 	    b2 = (b1 + 1) % bytes;
76 	    buf[i] = (tmp[b1] << s1) | (tmp[b2] >> s2);
77 	}
78 	free(tmp);
79     }
80     return 0;
81 }
82 
83 /* Add `b' to `a', both being one's complement numbers. */
84 static void
add1(unsigned char * a,unsigned char * b,size_t len)85 add1(unsigned char *a, unsigned char *b, size_t len)
86 {
87     int i;
88     int carry = 0;
89     for(i = len - 1; i >= 0; i--){
90 	int x = a[i] + b[i] + carry;
91 	carry = x > 0xff;
92 	a[i] = x & 0xff;
93     }
94     for(i = len - 1; carry && i >= 0; i--){
95 	int x = a[i] + carry;
96 	carry = x > 0xff;
97 	a[i] = x & 0xff;
98     }
99 }
100 
101 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_n_fold(const void * str,size_t len,void * key,size_t size)102 _krb5_n_fold(const void *str, size_t len, void *key, size_t size)
103 {
104     /* if len < size we need at most N * len bytes, ie < 2 * size;
105        if len > size we need at most 2 * len */
106     krb5_error_code ret = 0;
107     size_t maxlen = 2 * max(size, len);
108     size_t l = 0;
109     unsigned char *tmp = malloc(maxlen);
110     unsigned char *buf = malloc(len);
111 
112     if (tmp == NULL || buf == NULL) {
113         ret = ENOMEM;
114 	goto out;
115     }
116 
117     memcpy(buf, str, len);
118     memset(key, 0, size);
119     do {
120 	memcpy(tmp + l, buf, len);
121 	l += len;
122 	ret = rr13(buf, len * 8);
123 	if (ret)
124 	    goto out;
125 	while(l >= size) {
126 	    add1(key, tmp, size);
127 	    l -= size;
128 	    if(l == 0)
129 		break;
130 	    memmove(tmp, tmp + size, l);
131 	}
132     } while(l != 0);
133 out:
134     if (buf) {
135         memset(buf, 0, len);
136 	free(buf);
137     }
138     if (tmp) {
139         memset(tmp, 0, maxlen);
140 	free(tmp);
141     }
142     return ret;
143 }
144