⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keydb.c

📁 keyring是一种用于保护PALM中关键信息的系统
💻 C
字号:
/* -*- c-file-style: "java"; -*- * * $Header: /cvsroot/gnukeyring/keyring/keydb.c,v 1.46 2006/01/13 14:09:04 hoenicke Exp $ *  * Keyring -- store passwords securely on a handheld * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@users.sourceforge.net> * Copyright (C) 2001-2005 Jochen Hoenicke <hoenicke@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *//* TODO: Check that the terminating NULs in the strings are accounted * for correctly. */#include "includes.h"#define offsetof(str,fld) ((UInt16) &(((str *) NULL)->fld))Int16 gKeyDBCardNo;LocalID gKeyDBID;// Reference to the keys databaseDmOpenRef       gKeyDB;/* * True if the database can only be opened read-only; if e.g. the database is * stored in ROM. */Boolean g_ReadOnly;/* ====================================================================== * Key database * * All the keys are kept in a single PalmOS database.  Each record * begins with an unencrypted name, which is followed by a * 3DES-encrypted block containing all the other fields. * * We encrypt all the records with a key directly derived from the MD5 * hash of the master password.  This gives a 128 bit hash.  We split * this into two halves of 64 bits, and use them as DES encryption * keys K1 and K2.  (DES ignores a parity bit from each byte, so there * are actually only 56 unknown bits in each key.) * * As suggested in Schneier's ACv2, each block of the output is * encrypted as ENC(K1,DEC(K2,ENC(K1))).  Since we expect the records * to be relatively short, we don't worry about chaining blocks at the * moment: each is independently encrypted. * * We also need to be able to tell whether the user has entered the * right master password, since we want to give them an error message * rather than just display random garbage.  Therefore a salted hash * of the master password is also stored.  This goes into record #0. * * Rather than worrying about creating the reserved record when it's * used, we create them with the database so we know they'll never be * used.  These records are marked secret, because that flag is not * otherwise used in this application. * * When the user changes their password, we have to walk through the * database, decrypt each record with the old key, and re-encrypt with * the new key. *//* * Either check that the user's already said a read-only database is * OK, or ask them. */static Boolean Keyring_AcceptsReadOnly(void){     Boolean accepted = false;     Int16 size = sizeof accepted;     Int16 ret;     ret = PrefGetAppPreferences(kKeyringCreatorID,                                 prefID_ReadOnlyAccepted,                                 &accepted, &size,                                 true);     if (((ret == noPreferenceFound)          || (size != sizeof accepted)          || !accepted)) {	 if (FrmAlert(OfferReadOnlyAlert) == 0)	     accepted = true;     }     return accepted;}/* * Try to open an existing key database. *  * Will return an error if the database does not exist, in which case * you can try to create a new one.   */static Err KeyDB_OpenExistingDB(void) {     Err err;         // TODO: Give people the option to name the database, or to create     // it on different cards?     gKeyDB = DmOpenDatabaseByTypeCreator(kKeyDBType, kKeyringCreatorID,                                          dmModeReadWrite);     if (!gKeyDB)          return DmGetLastErr();     if ((err = DmOpenDatabaseInfo(gKeyDB, &gKeyDBID, NULL, NULL,                                   &gKeyDBCardNo, NULL)))          return err;     g_ReadOnly = false;     return 0;}static Err KeyDB_OpenReadOnly(void){     Err err;         // TODO: Give people the option to name the database, or to create     // it on different cards?     gKeyDB = DmOpenDatabaseByTypeCreator(kKeyDBType, kKeyringCreatorID,                                          dmModeReadOnly);     if (!gKeyDB)          return DmGetLastErr();     if ((err = DmOpenDatabaseInfo(gKeyDB, &gKeyDBID, NULL, NULL,                                   &gKeyDBCardNo, NULL)))          return err;     g_ReadOnly = true;     return 0;}/* * Create the reserved records that will contain the master password * check-hash.  We don't populate the record yet, but creating it here * means that later on we can just count on these records existing and * being in the right place. * * gKeyDB is open and refers to an empty database when this is called. * * At the moment we use only a single reserved record, but this * function can handle several. */Err KeyDB_CreateReservedRecords(void){    Err err;    Int16 i, idx;    UInt16 attr;    MemHandle recHandle;    for (i = 0; i < kNumHiddenRecs; i++) {	idx = i;	recHandle = DmNewRecord(gKeyDB, &idx, 1);	if (!recHandle) {	    err = DmGetLastErr();	    goto outErr;	}	ErrNonFatalDisplayIf(idx != i, __FUNCTION__ " inserted into wrong place");	if ((err = DmReleaseRecord(gKeyDB, idx, true)))	    goto outErr;	attr = dmRecAttrSecret | dmRecAttrDirty;	if ((err = DmSetRecordInfo(gKeyDB, idx, &attr, NULL)))	    goto outErr;    }    return 0; outErr:    UI_ReportSysError2(CreateDBAlert, err, __FUNCTION__);    return err;}Err KeyDB_CreateAppInfo(void){    LocalID      appInfoID;    MemHandle    appInfoHandle;    KrAppInfoPtr appInfoPtr;    UInt16       appInfoSize;#ifdef SUPPPORT_TEMPLATES    MemHandle    templateHandle;    UInt16       offset;    UInt8        *templatePtr, *templateBlock;    UInt8        numLabels;    UInt8        numTemplates;    UInt16       templateLength;    templateHandle = DmGetResource('TMPL', 1000);    templatePtr = templateBlock = MemHandleLock(templateHandle);    numLabels = 0;    numTemplates = 0;    templateLength = 0;    while (*templatePtr != 0) {	int namlen = StrLen(templatePtr);	templatePtr += namlen + 3;	numLabels++;    }    templatePtr++;    while (*templatePtr != 0) {	int namlen = StrLen(templatePtr);	int comps;	templatePtr += namlen + 1;	comps = *templatePtr;	templatePtr += comps + 1;	templateLength += namlen + 1 + comps + 1;	numTemplates++;    }#endif    appInfoSize = sizeof(KrAppInfoType);#ifdef SUPPPORT_TEMPLATES    appInfoSize += numLabels * sizeof(KrLabelType)	+ templateLength;#endif    appInfoHandle = DmNewHandle(gKeyDB, appInfoSize);    if (!appInfoHandle) {#ifdef SUPPPORT_TEMPLATES	MemHandleUnlock(templateHandle);	DmReleaseResource(templateHandle);#endif	return DmGetLastErr();    }        appInfoID = MemHandleToLocalID(appInfoHandle);    DmSetDatabaseInfo(gKeyDBCardNo, gKeyDBID,		      0,0,0,0,		      0,0,0,		      &appInfoID, 0,0,0);    appInfoPtr = MemLocalIDToLockedPtr(appInfoID, gKeyDBCardNo);    /* Clear the app info block. */    DmSet(appInfoPtr, 0, appInfoSize, 0);    /* Initialize the categories. */    CategoryInitialize(&appInfoPtr->categoryInfo, CategoryRsrc);    #ifdef SUPPPORT_TEMPLATES    DmWrite(appInfoPtr, offsetof(KrAppInfoType, numberOfLabels), 	    &numLabels, 1);    DmWrite(appInfoPtr, offsetof(KrAppInfoType, numberOfTemplates),	    &numTemplates, 1);    /* Initialize default fields. */    numLabels = 0;    offset    = sizeof(KrAppInfoType);    templatePtr = templateBlock;    while (*templatePtr != 0) {	int namlen = StrLen(templatePtr);	if (namlen > 16)	    namlen = 16;	DmWrite(appInfoPtr, offset, templatePtr, namlen);	offset += 16;	templatePtr += namlen + 1;	DmWrite(appInfoPtr, offset, templatePtr, 2);	templatePtr += 2;	offset += 2;    }    templatePtr++;    /* Initialize the templates. */    DmWrite(appInfoPtr, offset, templatePtr, templateLength);    MemHandleUnlock(templateHandle);    DmReleaseResource(templateHandle);#endif    MemPtrUnlock(appInfoPtr);    return 0;}Err KeyDB_SetDBInfo(Int16 cardNo, LocalID id) {    UInt16 version = kDatabaseVersion;    UInt16 attr;    DmDatabaseInfo(gKeyDBCardNo, gKeyDBID, NULL, &attr, NULL, NULL,		   NULL, NULL, NULL, NULL, NULL, NULL, NULL);    attr |= dmHdrAttrBackup;    return DmSetDatabaseInfo(cardNo, id,			     NULL, &attr, &version,			     NULL, NULL, NULL, NULL,			     NULL, NULL, NULL, NULL);}Err KeyDB_InitDB(char* newPasswd, Int16 cipher, Int16 iter){    SaltHashType salthash;    Err err;    if ((err = KeyDB_CreateAppInfo()))	return err;        err = PwHash_Create(newPasswd, cipher, iter, &salthash, NULL);    if (!err)	PwHash_Store(newPasswd, &salthash);    MemWipe(&salthash, sizeof(salthash));    return err;}#define KeyDB_GetVersion(ver) \    DmDatabaseInfo(gKeyDBCardNo, gKeyDBID, 0, 0, \		   ver, 0, 0, 0, 0, 0, 0, 0, 0)static Err KeyDB_CreateDB(void) {    Err err;    Char *newPasswd;    UInt16 cipher, iter;    newPasswd = SetPasswd_Ask(&cipher, &iter);    if (newPasswd == NULL)	return appCancelled;    gKeyDBCardNo = 0;    if ((err = DmCreateDatabase(gKeyDBCardNo, kKeyDBName,				kKeyringCreatorID, kKeyDBType,				false /* not resource */)))	goto outErr;    gKeyDBID = DmFindDatabase(gKeyDBCardNo, kKeyDBName);    if (!gKeyDBID)	goto outFindErr;    err = KeyDB_SetDBInfo(gKeyDBCardNo, gKeyDBID);    if (err)	goto outErr;    gKeyDB = DmOpenDatabase(gKeyDBCardNo, gKeyDBID, dmModeReadWrite);    if (!gKeyDB)	goto outFindErr;    err = KeyDB_InitDB(newPasswd, cipher, iter);    if (err)	goto outErr;    MemWipe(newPasswd, StrLen(newPasswd));    MemPtrFree(newPasswd);    return 0; outFindErr:    err = DmGetLastErr();     outErr:    MemWipe(newPasswd, StrLen(newPasswd));    MemPtrFree(newPasswd);    if (gKeyDB)	DmCloseDatabase(gKeyDB);    if (gKeyDBID)	DmDeleteDatabase(gKeyDBCardNo, gKeyDBID);    UI_ReportSysError2(CreateDBAlert, err, __FUNCTION__);    return err;}/* * Get everything going: either open an existing DB (converting if * necessary), or create a new one, or return an error. */Err KeyDB_Init(void){     Err    err;     UInt16 ver;         /* If the database doesn't already exist, then we require the user      * to set their password. */     err = KeyDB_OpenExistingDB();     switch (err) {     case errNone:	 break;     case dmErrReadOnly:     case dmErrROMBased:	 if (!Keyring_AcceptsReadOnly())	     return appCancelled;	 if ((err = KeyDB_OpenReadOnly()))	     goto failDB;	 break;	      case dmErrCantFind:	 if ((err = KeyDB_CreateDB()))	     return err;           /* error already reported */	 break;     default:	 	 goto failDB;     }     /* So, we opened a database OK.  Now, is it old, new, or	just right? */     if ((err = KeyDB_GetVersion(&ver))) {	 UI_ReportSysError2(KeyDatabaseAlert, err, __FUNCTION__);	 goto closeDB;     }     if (ver < kDatabaseVersion) {	 if (g_ReadOnly) {	     FrmAlert(UpgradeReadOnlyAlert);	     goto closeDB;	 }	 if ((err = UpgradeDB(ver))) {	     if (err != appErrMisc && err != appCancelled)		 UI_ReportSysError2(UpgradeFailedAlert, err, __FUNCTION__);	     goto closeDB;	 }     } else if (ver > kDatabaseVersion) {	 FrmAlert(TooNewAlert);	 goto closeDB;     }     if (!g_ReadOnly) {	 /* Sort Database just in case a backup program scrambled the	  * record order. */	 Keys_Sort();     }     /* Remember or clear the r/o state, so one doesn't need to reconfirm. */     PrefSetAppPreferences(kKeyringCreatorID, prefID_ReadOnlyAccepted,                           kAppVersion, 			   g_ReadOnly ? &g_ReadOnly : NULL, 			   g_ReadOnly ? sizeof(g_ReadOnly) : 0, true);     return 0; failDB:     UI_ReportSysError2(KeyDatabaseAlert, err, __FUNCTION__);     return err; closeDB:     DmCloseDatabase(gKeyDB);     gKeyDB = 0;     return err;}KrAppInfoPtr KeyDB_LockAppInfo(void) {    LocalID appInfoID = 0;    DmDatabaseInfo(gKeyDBCardNo, gKeyDBID, 0, 0, 0, 0,		   0, 0, 0, 		   &appInfoID, 0, 0, 0);    ErrFatalDisplayIf(appInfoID == 0, "AppInfo destroyed");    return MemLocalIDToLockedPtr(appInfoID, gKeyDBCardNo);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -