1/*
2 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7/*
8 * Copyright (c) 1990 Dennis Ferguson.  All rights reserved.
9 *
10 * Commercial use is permitted only if products which are derived from
11 * or include this software are made available for purchase and/or use
12 * in Canada.  Otherwise, redistribution and use in source and binary
13 * forms are permitted.
14 */
15
16/*
17 * des_cbc_encrypt.c - an implementation of the DES cipher function in cbc mode
18 */
19#include "des_int.h"
20
21/*
22 * des_cbc_encrypt - {en,de}crypt a stream in CBC mode
23 */
24
25/* SUNW14resync - sparcv9 cc complained about lack of object init */
26/* = all zero */
27const mit_des_cblock mit_des_zeroblock = {0, 0, 0, 0, 0, 0, 0, 0};
28
29#undef mit_des_cbc_encrypt
30
31#ifndef _KERNEL
32int
33mit_des_cbc_encrypt(context, in, out, length, key, ivec, encrypt)
34	krb5_context context;
35	const mit_des_cblock  *in;
36	mit_des_cblock  *out;
37	long length;
38	krb5_keyblock *key;
39	mit_des_cblock ivec;
40	int encrypt;
41{
42    krb5_error_code ret = KRB5_PROG_ETYPE_NOSUPP;
43    KRB5_MECH_TO_PKCS algos;
44    CK_MECHANISM mechanism;
45    CK_RV rv;
46    /* For the Key Object */
47
48    ret = 0;
49    if ((rv = get_algo(key->enctype, &algos)) != CKR_OK) {
50        KRB5_LOG0(KRB5_ERR, "failure to get algo id in function "
51            "mit_des_cbc_encrypt.");
52        ret = PKCS_ERR;
53        goto cleanup;
54    }
55
56    rv = init_key_uef(krb_ctx_hSession(context), key);
57    if (rv != CKR_OK) {
58        KRB5_LOG(KRB5_ERR, "init_key_uef failed in "
59		"mit_des_cbc_encrypt: rv = 0x%x", rv);
60        ret = PKCS_ERR;
61        goto cleanup;
62    }
63
64    mechanism.mechanism = algos.enc_algo;
65    mechanism.pParameter = ivec;
66    if (ivec != NULL)
67    	mechanism.ulParameterLen = MIT_DES_BLOCK_LENGTH;
68    else
69	mechanism.ulParameterLen = 0;
70
71    if (encrypt)
72        rv = C_EncryptInit(krb_ctx_hSession(context), &mechanism, key->hKey);
73    else
74        rv = C_DecryptInit(krb_ctx_hSession(context), &mechanism, key->hKey);
75
76    if (rv != CKR_OK) {
77        KRB5_LOG(KRB5_ERR, "C_EncryptInit/C_DecryptInit failed in "
78		"mit_des_cbc_encrypt: rv = 0x%x", rv);
79        ret = PKCS_ERR;
80        goto cleanup;
81    }
82
83    if (encrypt)
84	rv = C_Encrypt(krb_ctx_hSession(context), (CK_BYTE_PTR)in,
85	    (CK_ULONG)length, (CK_BYTE_PTR)out,
86	    (CK_ULONG_PTR)&length);
87    else
88	rv = C_Decrypt(krb_ctx_hSession(context), (CK_BYTE_PTR)in,
89	    (CK_ULONG)length, (CK_BYTE_PTR)out,
90	    (CK_ULONG_PTR)&length);
91
92    if (rv != CKR_OK) {
93            KRB5_LOG(KRB5_ERR,
94		"C_Encrypt/C_Decrypt failed in mit_des_cbc_encrypt: "
95                "rv = 0x%x", rv);
96            ret = PKCS_ERR;
97    }
98cleanup:
99
100final_cleanup:
101    if (ret)
102        (void) memset(out, 0, length);
103
104    KRB5_LOG(KRB5_INFO, "mit_des_cbc_encrypt() end retval=%d", ret);
105
106    return(ret);
107}
108#else
109
110/*
111 * This routine performs DES cipher-block-chaining operation, either
112 * encrypting from cleartext to ciphertext, if encrypt != 0 or
113 * decrypting from ciphertext to cleartext, if encrypt == 0.
114 *
115 * The key schedule is passed as an arg, as well as the cleartext or
116 * ciphertext.  The cleartext and ciphertext should be in host order.
117 *
118 * NOTE-- the output is ALWAYS an multiple of 8 bytes long.  If not
119 * enough space was provided, your program will get trashed.
120 *
121 * For encryption, the cleartext string is null padded, at the end, to
122 * an integral multiple of eight bytes.
123 *
124 * For decryption, the ciphertext will be used in integral multiples
125 * of 8 bytes, but only the first "length" bytes returned into the
126 * cleartext.
127 */
128
129/* ARGSUSED */
130int
131mit_des_cbc_encrypt(krb5_context context,
132	const mit_des_cblock *in,
133	mit_des_cblock *out,
134	long length, krb5_keyblock *key,
135	mit_des_cblock ivec, int encrypt)
136{
137	int ret = KRB5_PROG_ETYPE_NOSUPP;
138	krb5_data ivdata;
139	ret = 0;
140
141	KRB5_LOG(KRB5_INFO, "mit_des_cbc_encrypt() start encrypt=%d", encrypt);
142
143	ivdata.data = (char *)ivec;
144	ivdata.length = sizeof(mit_des_cblock);
145
146	ret = k5_ef_crypto((const char *)in,
147			(char *)out, length, key, &ivdata, encrypt);
148
149	KRB5_LOG(KRB5_INFO, "mit_des_cbc_encrypt() end retval=%d", ret);
150	return(ret);
151}
152#endif /* !_KERNEL */
153