/* * sm-common.c: Common cryptographic procedures related to * Secure Messaging * * Copyright (C) 2010 Viktor Tarasov * OpenTrust * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #ifndef ENABLE_OPENSSL #error "Need OpenSSL" #endif #include #include #include "libopensc/opensc.h" #include "libopensc/asn1.h" #include "libopensc/log.h" #include "sm-common.h" /* * From crypto/des/des_locl.h of OpenSSL . */ #define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \ l|=((DES_LONG)(*((c)++)))<< 8L, \ l|=((DES_LONG)(*((c)++)))<<16L, \ l|=((DES_LONG)(*((c)++)))<<24L) #define c2ln(c,l1,l2,n) { \ c+=n; \ l1=l2=0; \ switch (n) { \ case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \ /* fall through */ \ case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \ /* fall through */ \ case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \ /* fall through */ \ case 5: l2|=((DES_LONG)(*(--(c)))); \ /* fall through */ \ case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \ /* fall through */ \ case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \ /* fall through */ \ case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \ /* fall through */ \ case 1: l1|=((DES_LONG)(*(--(c)))); \ } \ } #define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ *((c)++)=(unsigned char)(((l)>>24L)&0xff)) /* * Inspired by or taken from OpenSSL crypto/des/cbc3_enc.c */ static void DES_3cbc_encrypt(DES_cblock *input, DES_cblock *output, long length, DES_key_schedule *ks1, DES_key_schedule *ks2, DES_cblock *iv, int enc) { int off=((int)length-1)/8; long l8=((length+7)/8)*8; DES_cblock icv_out; memset(&icv_out, 0, sizeof(icv_out)); if (enc == DES_ENCRYPT) { DES_cbc_encrypt((unsigned char*)input, (unsigned char*)output,length,ks1,iv,enc); DES_cbc_encrypt((unsigned char*)output, (unsigned char*)output,l8,ks2,iv,!enc); DES_cbc_encrypt((unsigned char*)output, (unsigned char*)output,l8,ks1,iv,enc); if ((unsigned)length >= sizeof(DES_cblock)) memcpy(icv_out,output[off],sizeof(DES_cblock)); } else { if ((unsigned)length >= sizeof(DES_cblock)) memcpy(icv_out,input[off],sizeof(DES_cblock)); DES_cbc_encrypt((unsigned char*)input, (unsigned char*)output,l8,ks1,iv,enc); DES_cbc_encrypt((unsigned char*)output, (unsigned char*)output,l8,ks2,iv,!enc); DES_cbc_encrypt((unsigned char*)output, (unsigned char*)output,length,ks1,iv,enc); } memcpy(*iv,icv_out,sizeof(DES_cblock)); } DES_LONG DES_cbc_cksum_3des_emv96(const unsigned char *in, DES_cblock *output, long length, DES_key_schedule *schedule, DES_key_schedule *schedule2, const_DES_cblock *ivec) { register DES_LONG tout0,tout1,tin0,tin1; register long l=length; DES_LONG tin[2]; unsigned char *out = &(*output)[0]; const unsigned char *iv = &(*ivec)[0]; c2l(iv,tout0); c2l(iv,tout1); for (; l>8; l-=8) { if (l >= 16) { c2l(in,tin0); c2l(in,tin1); } else c2ln(in,tin0,tin1,l); tin0^=tout0; tin[0]=tin0; tin1^=tout1; tin[1]=tin1; DES_encrypt1((DES_LONG *)tin,schedule, DES_ENCRYPT); tout0=tin[0]; tout1=tin[1]; } if (l == 8) { c2l(in,tin0); c2l(in,tin1); } else c2ln(in,tin0,tin1,l); tin0^=tout0; tin[0]=tin0; tin1^=tout1; tin[1]=tin1; DES_encrypt3((DES_LONG *)tin,schedule,schedule2,schedule); tout1=tin[1]; if (out != NULL) { l2c(tout0,out); l2c(tout1,out); } /* Transform the data in tout1 so that it will match the return value that the MIT Kerberos mit_des_cbc_cksum API returns. */ tout1 = ((tout1 >> 24L) & 0x000000FF) | ((tout1 >> 8L) & 0x0000FF00) | ((tout1 << 8L) & 0x00FF0000) | ((tout1 << 24L) & 0xFF000000); return(tout1); } DES_LONG DES_cbc_cksum_3des(const unsigned char *in, DES_cblock *output, long length, DES_key_schedule *schedule, DES_key_schedule *schedule2, const_DES_cblock *ivec) { register DES_LONG tout0,tout1,tin0,tin1; register long l=length; DES_LONG tin[2]; unsigned char *out = &(*output)[0]; const unsigned char *iv = &(*ivec)[0]; c2l(iv,tout0); c2l(iv,tout1); for (; l>0; l-=8) { if (l >= 8) { c2l(in,tin0); c2l(in,tin1); } else c2ln(in,tin0,tin1,l); tin0^=tout0; tin[0]=tin0; tin1^=tout1; tin[1]=tin1; DES_encrypt3((DES_LONG *)tin,schedule,schedule2,schedule); /* fix 15/10/91 eay - thanks to keithr@sco.COM */ tout0=tin[0]; tout1=tin[1]; } if (out != NULL) { l2c(tout0,out); l2c(tout1,out); } /* Transform the data in tout1 so that it will match the return value that the MIT Kerberos mit_des_cbc_cksum API returns. */ tout1 = ((tout1 >> 24L) & 0x000000FF) | ((tout1 >> 8L) & 0x0000FF00) | ((tout1 << 8L) & 0x00FF0000) | ((tout1 << 24L) & 0xFF000000); return(tout1); } int sm_encrypt_des_ecb3(unsigned char *key, unsigned char *data, int data_len, unsigned char **out, int *out_len) { int ii; DES_cblock kk,k2; DES_key_schedule ks,ks2; if (!out || !out_len) return -1; *out_len = data_len + 7; *out_len -= *out_len % 8; *out = malloc(*out_len); if (!(*out)) return -1; memcpy(&kk, key, 8); memcpy(&k2, key + 8, 8); DES_set_key_unchecked(&kk,&ks); DES_set_key_unchecked(&k2,&ks2); for (ii=0; ii= 0; ii--) { *(ssc + ii) += 1; if (*(ssc + ii) != 0) break; } }