|
/***************************************************************************
|
|
begin : Mon Dec 01 2008
|
|
copyright : (C) 2008 by Martin Preuss
|
|
email : martin@libchipcard.de
|
|
|
|
***************************************************************************
|
|
* Please see toplevel file COPYING for license details *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#define DISABLE_DEBUGLOG
|
|
|
|
|
|
#include "cryptmgrkeys_p.h"
|
|
#include "i18n_l.h"
|
|
#include <gwenhywfar/misc.h>
|
|
#include <gwenhywfar/debug.h>
|
|
#include <gwenhywfar/mdigest.h>
|
|
#include <gwenhywfar/padd.h>
|
|
#include <gwenhywfar/crypthead.h>
|
|
#include <gwenhywfar/text.h>
|
|
|
|
|
|
|
|
GWEN_INHERIT(GWEN_CRYPTMGR, GWEN_CRYPTMGR_KEYS);
|
|
|
|
|
|
|
|
GWEN_CRYPTMGR *GWEN_CryptMgrKeys_new(const char *localName,
|
|
GWEN_CRYPT_KEY *localKey,
|
|
const char *peerName,
|
|
GWEN_CRYPT_KEY *peerKey,
|
|
int ownKeys) {
|
|
GWEN_CRYPTMGR *cm;
|
|
GWEN_CRYPTMGR_KEYS *xcm;
|
|
|
|
cm=GWEN_CryptMgr_new();
|
|
GWEN_NEW_OBJECT(GWEN_CRYPTMGR_KEYS, xcm);
|
|
GWEN_INHERIT_SETDATA(GWEN_CRYPTMGR, GWEN_CRYPTMGR_KEYS, cm, xcm,
|
|
GWEN_CryptMgrKeys_FreeData);
|
|
|
|
if (localKey) {
|
|
xcm->localKey=localKey;
|
|
GWEN_CryptMgr_SetLocalKeyNumber(cm, GWEN_Crypt_Key_GetKeyNumber(localKey));
|
|
GWEN_CryptMgr_SetLocalKeyVersion(cm, GWEN_Crypt_Key_GetKeyVersion(localKey));
|
|
}
|
|
else
|
|
xcm->ownLocalKey=0;
|
|
|
|
if (peerKey) {
|
|
xcm->peerKey=peerKey;
|
|
GWEN_CryptMgr_SetPeerKeyNumber(cm, GWEN_Crypt_Key_GetKeyNumber(peerKey));
|
|
GWEN_CryptMgr_SetPeerKeyVersion(cm, GWEN_Crypt_Key_GetKeyVersion(peerKey));
|
|
xcm->ownPeerKey=ownKeys;
|
|
}
|
|
else
|
|
xcm->ownPeerKey=0;
|
|
|
|
if (localName)
|
|
GWEN_CryptMgr_SetLocalKeyName(cm, localName);
|
|
|
|
if (peerName)
|
|
GWEN_CryptMgr_SetPeerKeyName(cm, peerName);
|
|
|
|
GWEN_CryptMgr_SetSignDataFn(cm, GWEN_CryptMgrKeys_SignData);
|
|
GWEN_CryptMgr_SetVerifyDataFn(cm, GWEN_CryptMgrKeys_VerifyData);
|
|
GWEN_CryptMgr_SetEncryptKeyFn(cm, GWEN_CryptMgrKeys_EncryptKey);
|
|
GWEN_CryptMgr_SetDecryptKeyFn(cm, GWEN_CryptMgrKeys_DecryptKey);
|
|
|
|
return cm;
|
|
}
|
|
|
|
|
|
|
|
GWENHYWFAR_CB
|
|
void GWEN_CryptMgrKeys_FreeData(GWEN_UNUSED void *bp, void *p) {
|
|
GWEN_CRYPTMGR_KEYS *xcm;
|
|
|
|
xcm=(GWEN_CRYPTMGR_KEYS*) p;
|
|
|
|
if (xcm->ownLocalKey)
|
|
GWEN_Crypt_Key_free(xcm->localKey);
|
|
if (xcm->ownPeerKey)
|
|
GWEN_Crypt_Key_free(xcm->peerKey);
|
|
}
|
|
|
|
|
|
|
|
void GWEN_CryptMgrKeys_SetPeerKey(GWEN_CRYPTMGR *cm,
|
|
GWEN_CRYPT_KEY *peerKey,
|
|
int ownKey) {
|
|
GWEN_CRYPTMGR_KEYS *xcm;
|
|
|
|
assert(cm);
|
|
xcm=GWEN_INHERIT_GETDATA(GWEN_CRYPTMGR, GWEN_CRYPTMGR_KEYS, cm);
|
|
assert(xcm);
|
|
|
|
if (xcm->ownPeerKey)
|
|
GWEN_Crypt_Key_free(xcm->peerKey);
|
|
xcm->peerKey=peerKey;
|
|
xcm->ownPeerKey=ownKey;
|
|
}
|
|
|
|
|
|
|
|
GWENHYWFAR_CB
|
|
int GWEN_CryptMgrKeys_SignData(GWEN_CRYPTMGR *cm,
|
|
const uint8_t *pData, uint32_t lData,
|
|
GWEN_BUFFER *dbuf) {
|
|
GWEN_CRYPTMGR_KEYS *xcm;
|
|
GWEN_MDIGEST *md;
|
|
int rv;
|
|
GWEN_BUFFER *tbuf;
|
|
int ksize;
|
|
uint32_t signatureLen;
|
|
|
|
assert(cm);
|
|
xcm=GWEN_INHERIT_GETDATA(GWEN_CRYPTMGR, GWEN_CRYPTMGR_KEYS, cm);
|
|
assert(xcm);
|
|
|
|
if (xcm->localKey==NULL) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No local key");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
|
|
ksize=GWEN_Crypt_Key_GetKeySize(xcm->localKey);
|
|
|
|
/* hash pData */
|
|
md=GWEN_MDigest_Rmd160_new();
|
|
rv=GWEN_MDigest_Begin(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
rv=GWEN_MDigest_Update(md, pData, lData);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
rv=GWEN_MDigest_End(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* padd */
|
|
tbuf=GWEN_Buffer_new(0, ksize, 0, 1);
|
|
GWEN_Buffer_AppendBytes(tbuf,
|
|
(const char*)GWEN_MDigest_GetDigestPtr(md),
|
|
GWEN_MDigest_GetDigestSize(md));
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Padd_PaddWithIso9796_2(tbuf, ksize);
|
|
|
|
/* sign */
|
|
GWEN_Buffer_AllocRoom(dbuf, ksize);
|
|
signatureLen=GWEN_Buffer_GetMaxUnsegmentedWrite(dbuf);
|
|
rv=GWEN_Crypt_Key_Sign(xcm->localKey,
|
|
(uint8_t*)GWEN_Buffer_GetStart(tbuf),
|
|
GWEN_Buffer_GetUsedBytes(tbuf),
|
|
(uint8_t*)GWEN_Buffer_GetPosPointer(dbuf),
|
|
&signatureLen);
|
|
GWEN_Buffer_free(tbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
GWEN_Buffer_IncrementPos(dbuf, signatureLen);
|
|
GWEN_Buffer_AdjustUsedBytes(dbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWENHYWFAR_CB
|
|
int GWEN_CryptMgrKeys_VerifyData(GWEN_CRYPTMGR *cm,
|
|
const uint8_t *pData, uint32_t lData,
|
|
const uint8_t *pSignature, uint32_t lSignature) {
|
|
GWEN_CRYPTMGR_KEYS *xcm;
|
|
GWEN_MDIGEST *md;
|
|
int rv;
|
|
GWEN_BUFFER *tbuf;
|
|
int ksize;
|
|
uint32_t l;
|
|
|
|
assert(cm);
|
|
xcm=GWEN_INHERIT_GETDATA(GWEN_CRYPTMGR, GWEN_CRYPTMGR_KEYS, cm);
|
|
assert(xcm);
|
|
|
|
if (xcm->peerKey==NULL) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No peer key");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
|
|
ksize=GWEN_Crypt_Key_GetKeySize(xcm->peerKey);
|
|
|
|
/* the padding algo uses random numbers, so we must use the encrypt function and
|
|
* compare the decoded and unpadded signature with the hash of the source data
|
|
*/
|
|
tbuf=GWEN_Buffer_new(0, ksize+16, 0, 1);
|
|
l=GWEN_Buffer_GetMaxUnsegmentedWrite(tbuf);
|
|
rv=GWEN_Crypt_Key_Encipher(xcm->peerKey,
|
|
pSignature, lSignature,
|
|
(uint8_t*)GWEN_Buffer_GetPosPointer(tbuf),
|
|
&l);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(tbuf);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(tbuf, l);
|
|
GWEN_Buffer_AdjustUsedBytes(tbuf);
|
|
|
|
/* unpadd */
|
|
rv=GWEN_Padd_UnpaddWithIso9796_2(tbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(tbuf);
|
|
return rv;
|
|
}
|
|
/* tbuf now contains the hash */
|
|
|
|
/* hash source data */
|
|
md=GWEN_MDigest_Rmd160_new();
|
|
rv=GWEN_MDigest_Begin(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(tbuf);
|
|
return rv;
|
|
}
|
|
rv=GWEN_MDigest_Update(md, pData, lData);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(tbuf);
|
|
return rv;
|
|
}
|
|
rv=GWEN_MDigest_End(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(tbuf);
|
|
return rv;
|
|
}
|
|
|
|
if (GWEN_MDigest_GetDigestSize(md)!=GWEN_Buffer_GetUsedBytes(tbuf)) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Invalid signature");
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(tbuf);
|
|
return GWEN_ERROR_VERIFY;
|
|
}
|
|
|
|
if (memcmp(GWEN_MDigest_GetDigestPtr(md),
|
|
GWEN_Buffer_GetStart(tbuf),
|
|
GWEN_MDigest_GetDigestSize(md))!=0) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Invalid signature");
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(tbuf);
|
|
return GWEN_ERROR_VERIFY;
|
|
}
|
|
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(tbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWENHYWFAR_CB
|
|
int GWEN_CryptMgrKeys_EncryptKey(GWEN_CRYPTMGR *cm,
|
|
const uint8_t *pData, uint32_t lData,
|
|
GWEN_BUFFER *dbuf) {
|
|
GWEN_CRYPTMGR_KEYS *xcm;
|
|
int rv;
|
|
GWEN_BUFFER *tbuf;
|
|
int ksize;
|
|
uint32_t l;
|
|
|
|
assert(cm);
|
|
xcm=GWEN_INHERIT_GETDATA(GWEN_CRYPTMGR, GWEN_CRYPTMGR_KEYS, cm);
|
|
assert(xcm);
|
|
|
|
if (xcm->peerKey==NULL) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No peer key");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
|
|
ksize=GWEN_Crypt_Key_GetKeySize(xcm->peerKey);
|
|
|
|
/* padd key data */
|
|
tbuf=GWEN_Buffer_new(0, ksize, 0, 1);
|
|
GWEN_Buffer_AppendBytes(tbuf, (const char*) pData, lData);
|
|
rv=GWEN_Padd_PaddWithIso9796_2(tbuf, ksize);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(tbuf);
|
|
return rv;
|
|
}
|
|
|
|
GWEN_Buffer_AllocRoom(dbuf, ksize);
|
|
l=GWEN_Buffer_GetMaxUnsegmentedWrite(dbuf);
|
|
rv=GWEN_Crypt_Key_Encipher(xcm->peerKey,
|
|
(const uint8_t*)GWEN_Buffer_GetStart(tbuf),
|
|
GWEN_Buffer_GetUsedBytes(tbuf),
|
|
(uint8_t*)GWEN_Buffer_GetPosPointer(dbuf),
|
|
&l);
|
|
GWEN_Buffer_free(tbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
GWEN_Buffer_IncrementPos(dbuf, l);
|
|
GWEN_Buffer_AdjustUsedBytes(dbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWENHYWFAR_CB
|
|
int GWEN_CryptMgrKeys_DecryptKey(GWEN_CRYPTMGR *cm,
|
|
const uint8_t *pData, uint32_t lData,
|
|
GWEN_BUFFER *dbuf) {
|
|
GWEN_CRYPTMGR_KEYS *xcm;
|
|
int rv;
|
|
GWEN_BUFFER *tbuf;
|
|
int ksize;
|
|
uint32_t l;
|
|
|
|
assert(cm);
|
|
xcm=GWEN_INHERIT_GETDATA(GWEN_CRYPTMGR, GWEN_CRYPTMGR_KEYS, cm);
|
|
assert(xcm);
|
|
|
|
if (xcm->localKey==NULL) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No local key");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
|
|
ksize=GWEN_Crypt_Key_GetKeySize(xcm->localKey);
|
|
|
|
tbuf=GWEN_Buffer_new(0, ksize, 0, 1);
|
|
l=GWEN_Buffer_GetMaxUnsegmentedWrite(tbuf);
|
|
rv=GWEN_Crypt_Key_Decipher(xcm->localKey,
|
|
pData, lData,
|
|
(uint8_t*)GWEN_Buffer_GetPosPointer(tbuf),
|
|
&l);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(tbuf);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(tbuf, l);
|
|
GWEN_Buffer_AdjustUsedBytes(tbuf);
|
|
|
|
/* unpadd data */
|
|
rv=GWEN_Padd_UnpaddWithIso9796_2(tbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(tbuf);
|
|
return rv;
|
|
}
|
|
|
|
GWEN_Buffer_AppendBuffer(dbuf, tbuf);
|
|
GWEN_Buffer_free(tbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|