summaryrefslogtreecommitdiff
path: root/usr/src/lib/libresolv2/common/dnssafe/seccbcd.c
blob: b88d6f94383ffa7b49c325adc34084355269eea5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 * Copyright (c) 1999 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
   unpublished work protected as such under copyright law.  This work
   contains proprietary, confidential, and trade secret information of
   RSA Data Security, Inc.  Use, disclosure or reproduction without the
   express written authorization of RSA Data Security, Inc. is
   prohibited.
 */

#include "port_before.h"
#include "global.h"
#include "algae.h"
#include "secrcbc.h"
#include "port_after.h"

static void SecretCBCDecryptBlock PROTO_LIST
  ((POINTER, unsigned char *, SECRET_CRYPT, unsigned char *,
    unsigned char *));

/* On first call, it is assumed that *remainderLen is zero.
   This assumes remainder buffer is at least 16 bytes is size.
   Returns AE_OUTPUT_LEN, 0.
 */
int SecretCBCDecryptUpdate
  (context, xorBlock, remainder, remainderLen, SecretDecrypt, output,
   outputLen, maxOutputLen, input, inputLen)
POINTER context;
unsigned char *xorBlock;
unsigned char *remainder;
unsigned int *remainderLen;
SECRET_CRYPT SecretDecrypt;
unsigned char *output;
unsigned int *outputLen;
unsigned int maxOutputLen;
unsigned char *input;
unsigned int inputLen;
{
  unsigned int partialLen;

  if (*remainderLen + inputLen <= 16) {
    /* Not enough to decrypt, just accumulate into remainder.
     */
    *outputLen = 0;
    T_memcpy ((POINTER)remainder + *remainderLen, (POINTER)input, inputLen);
    *remainderLen += inputLen;
    return (0);
  }

  /* Fill up the rest of the remainder with bytes from input.
   */
  T_memcpy
    ((POINTER)remainder + *remainderLen, (POINTER)input,
     partialLen = 16 - *remainderLen);
  input += partialLen;
  inputLen -= partialLen;    

  /* remainder is full and inputLen is at least 1.  Compute outputLen
       as the size needed to keep remainder as full as possible.
   */
  if ((*outputLen = 8 * ((inputLen + 7) / 8)) > maxOutputLen)
    return (AE_OUTPUT_LEN);

  SecretCBCDecryptBlock
    (context, xorBlock, SecretDecrypt, output, remainder);
  output += 8;
  
  if (inputLen <= 8) {
    /* Shift remaining input bytes into remainder */
    T_memmove ((POINTER)remainder, (POINTER)(remainder + 8), 8);
    T_memcpy ((POINTER)(remainder + 8), (POINTER)input, inputLen);
    *remainderLen = 8 + inputLen;
    return (0);
  }

  /* Decrypt the rest of the remainder.
   */
  SecretCBCDecryptBlock
    (context, xorBlock, SecretDecrypt, output, remainder + 8);
  output += 8;

  /* Now decrypt the bulk of the input.
   */
  while (inputLen > 16) {
    SecretCBCDecryptBlock (context, xorBlock, SecretDecrypt, output, input);
    output += 8;
    input += 8;
    inputLen -= 8;
  }

  /* inputLen is now <= 16, so copy input to remainder.
   */
  T_memcpy ((POINTER)remainder, (POINTER)input, inputLen);
  *remainderLen = inputLen;
  return (0);
}

/* The caller must restart the context (setting remainderLen to zero).
   Returns AE_INPUT_LEN, AE_OUTPUT_LEN, 0.
 */
int SecretCBCDecryptFinal
  (context, xorBlock, remainder, remainderLen, SecretDecrypt, output,
   outputLen, maxOutputLen)
POINTER context;
unsigned char *xorBlock;
unsigned char *remainder;
unsigned int remainderLen;
SECRET_CRYPT SecretDecrypt;
unsigned char *output;
unsigned int *outputLen;
unsigned int maxOutputLen;
{
  if ((*outputLen = remainderLen) == 0)
    /* There was never any data. */
    return (0);
  
  if (remainderLen != 8 && remainderLen != 16)
    return (AE_INPUT_LEN);

  if (*outputLen > maxOutputLen)
    return (AE_OUTPUT_LEN);

  SecretCBCDecryptBlock
    (context, xorBlock, SecretDecrypt, output, remainder);
  output += 8;
  if (remainderLen == 16)
    SecretCBCDecryptBlock
      (context, xorBlock, SecretDecrypt, output, remainder + 8);
  return (0);
}

static void SecretCBCDecryptBlock (context, xorBlock, SecretDecrypt, out, in)
POINTER context;
unsigned char *xorBlock;
SECRET_CRYPT SecretDecrypt;
unsigned char *out;
unsigned char *in;
{
  unsigned char tempBuffer[8];
  unsigned int i;
  
  /* Save input to be copied to the xor block. */
  T_memcpy ((POINTER)tempBuffer, (POINTER)in, 8);
  (*SecretDecrypt) (context, out, in);
  for (i = 0; i < 8; i++)
    out[i] ^= xorBlock[i];  
  T_memcpy ((POINTER)xorBlock, (POINTER)tempBuffer, 8);
  
  T_memset ((POINTER)tempBuffer, 0, sizeof (tempBuffer));
}