155682Smarkm/*
2233294Sstas * Copyright (c) 1999 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of KTH nor the names of its contributors may be
1855682Smarkm *    used to endorse or promote products derived from this software without
1955682Smarkm *    specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
2255682Smarkm * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2455682Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
2555682Smarkm * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2655682Smarkm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2755682Smarkm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2855682Smarkm * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2955682Smarkm * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
3055682Smarkm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
3155682Smarkm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
3255682Smarkm
3355682Smarkm#include "krb5_locl.h"
3455682Smarkm
35178825Sdfrstatic krb5_error_code
3655682Smarkmrr13(unsigned char *buf, size_t len)
3755682Smarkm{
3855682Smarkm    unsigned char *tmp;
3955682Smarkm    int bytes = (len + 7) / 8;
4055682Smarkm    int i;
4155682Smarkm    if(len == 0)
42178825Sdfr	return 0;
4355682Smarkm    {
4455682Smarkm	const int bits = 13 % len;
4555682Smarkm	const int lbit = len % 8;
46233294Sstas
4755682Smarkm	tmp = malloc(bytes);
48178825Sdfr	if (tmp == NULL)
49178825Sdfr	    return ENOMEM;
5055682Smarkm	memcpy(tmp, buf, bytes);
5155682Smarkm	if(lbit) {
5255682Smarkm	    /* pad final byte with inital bits */
5355682Smarkm	    tmp[bytes - 1] &= 0xff << (8 - lbit);
5455682Smarkm	    for(i = lbit; i < 8; i += len)
5555682Smarkm		tmp[bytes - 1] |= buf[0] >> i;
5655682Smarkm	}
5755682Smarkm	for(i = 0; i < bytes; i++) {
5855682Smarkm	    int bb;
5955682Smarkm	    int b1, s1, b2, s2;
6055682Smarkm	    /* calculate first bit position of this byte */
6155682Smarkm	    bb = 8 * i - bits;
6255682Smarkm	    while(bb < 0)
6355682Smarkm		bb += len;
6455682Smarkm	    /* byte offset and shift count */
6555682Smarkm	    b1 = bb / 8;
6655682Smarkm	    s1 = bb % 8;
67233294Sstas
68233294Sstas	    if(bb + 8 > bytes * 8)
6955682Smarkm		/* watch for wraparound */
7055682Smarkm		s2 = (len + 8 - s1) % 8;
71233294Sstas	    else
7255682Smarkm		s2 = 8 - s1;
7355682Smarkm	    b2 = (b1 + 1) % bytes;
7455682Smarkm	    buf[i] = (tmp[b1] << s1) | (tmp[b2] >> s2);
7555682Smarkm	}
7655682Smarkm	free(tmp);
7755682Smarkm    }
78178825Sdfr    return 0;
7955682Smarkm}
8055682Smarkm
81178825Sdfr/* Add `b' to `a', both being one's complement numbers. */
8255682Smarkmstatic void
8355682Smarkmadd1(unsigned char *a, unsigned char *b, size_t len)
8455682Smarkm{
8555682Smarkm    int i;
8655682Smarkm    int carry = 0;
8755682Smarkm    for(i = len - 1; i >= 0; i--){
8855682Smarkm	int x = a[i] + b[i] + carry;
8955682Smarkm	carry = x > 0xff;
9055682Smarkm	a[i] = x & 0xff;
9155682Smarkm    }
9255682Smarkm    for(i = len - 1; carry && i >= 0; i--){
9355682Smarkm	int x = a[i] + carry;
9455682Smarkm	carry = x > 0xff;
9555682Smarkm	a[i] = x & 0xff;
9655682Smarkm    }
9755682Smarkm}
9855682Smarkm
99233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
10055682Smarkm_krb5_n_fold(const void *str, size_t len, void *key, size_t size)
10155682Smarkm{
10255682Smarkm    /* if len < size we need at most N * len bytes, ie < 2 * size;
10355682Smarkm       if len > size we need at most 2 * len */
104178825Sdfr    krb5_error_code ret = 0;
10555682Smarkm    size_t maxlen = 2 * max(size, len);
10655682Smarkm    size_t l = 0;
10755682Smarkm    unsigned char *tmp = malloc(maxlen);
10855682Smarkm    unsigned char *buf = malloc(len);
109178825Sdfr
110233294Sstas    if (tmp == NULL || buf == NULL) {
111233294Sstas        ret = ENOMEM;
112233294Sstas	goto out;
113233294Sstas    }
114233294Sstas
11555682Smarkm    memcpy(buf, str, len);
11655682Smarkm    memset(key, 0, size);
11755682Smarkm    do {
11855682Smarkm	memcpy(tmp + l, buf, len);
11955682Smarkm	l += len;
120178825Sdfr	ret = rr13(buf, len * 8);
121178825Sdfr	if (ret)
122178825Sdfr	    goto out;
12355682Smarkm	while(l >= size) {
12455682Smarkm	    add1(key, tmp, size);
12555682Smarkm	    l -= size;
12655682Smarkm	    if(l == 0)
12755682Smarkm		break;
12855682Smarkm	    memmove(tmp, tmp + size, l);
12955682Smarkm	}
13055682Smarkm    } while(l != 0);
131178825Sdfrout:
132233294Sstas    if (buf) {
133233294Sstas        memset(buf, 0, len);
134233294Sstas	free(buf);
135233294Sstas    }
136233294Sstas    if (tmp) {
137233294Sstas        memset(tmp, 0, maxlen);
138233294Sstas	free(tmp);
139233294Sstas    }
140178825Sdfr    return ret;
14155682Smarkm}
142