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