//----------------------------------------------------------------------------- // swCryptEncryptData() //----------------------------------------------------------------------------- // [in] iv = vecteur d'initialisation // [in/out] pData = pointeur vers les données à chiffrer / chiffrées // [in] lData = taille des données à chiffrer (lData en entrée = lData en sortie) // [in] hKey = clé de chiffrement //----------------------------------------------------------------------------- // Retour : 0 si OK //----------------------------------------------------------------------------- int swCryptEncryptData(unsigned char *iv, unsigned char *pData,DWORD lData,HCRYPTKEY hKey) { TRACE((TRACE_ENTER,_F_,"")); BOOL brc; int rc=-1; DWORD dwMode=CRYPT_MODE_CBC; brc=CryptSetKeyParam(hKey,KP_IV,iv,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptSetKeyParam(KP_IV)")); goto end; } brc=CryptSetKeyParam(hKey,KP_MODE,(BYTE*)&dwMode,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptSetKeyParam(KP_MODE)")); goto end; } brc=CryptEncrypt(hKey,0,TRUE,0,pData,&lData,lData+16); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptEncrypt()=0x%08lx",GetLastError())); goto end; } TRACE_BUFFER((TRACE_DEBUG,_F_,iv,16,"iv")); TRACE_BUFFER((TRACE_DEBUG,_F_,pData,64,"Donnees chiffrees")); TRACE_BUFFER((TRACE_DEBUG,_F_,pData+64,16,"ov")); rc=0; end: TRACE((TRACE_LEAVE,_F_,"rc=%d",rc)); return rc; }
//----------------------------------------------------------------------------- // swReadPBKDF2Salt() //----------------------------------------------------------------------------- // Lit les sels dans le .ini //----------------------------------------------------------------------------- int swReadPBKDF2Salt(void) { TRACE((TRACE_ENTER,_F_, "")); int rc=-1; char szPBKDF2Salt[PBKDF2_SALT_LEN*2+1]; // Lecture du sel mot de passe GetPrivateProfileString("swSSO","pwdSalt","",szPBKDF2Salt,sizeof(szPBKDF2Salt),gszCfgFile); if (strlen(szPBKDF2Salt)!=PBKDF2_SALT_LEN*2) goto end; swCryptDecodeBase64(szPBKDF2Salt,(char*)gSalts.bufPBKDF2PwdSalt,PBKDF2_SALT_LEN); gSalts.bPBKDF2PwdSaltReady=TRUE; TRACE_BUFFER((TRACE_DEBUG,_F_,gSalts.bufPBKDF2PwdSalt,PBKDF2_SALT_LEN,"gbufPBKDF2PwdSalt")); // Lecture du sel dérivation de clé GetPrivateProfileString("swSSO","keySalt","",szPBKDF2Salt,sizeof(szPBKDF2Salt),gszCfgFile); if (strlen(szPBKDF2Salt)!=PBKDF2_SALT_LEN*2) goto end; swCryptDecodeBase64(szPBKDF2Salt,(char*)gSalts.bufPBKDF2KeySalt,PBKDF2_SALT_LEN); gSalts.bPBKDF2KeySaltReady=TRUE; TRACE_BUFFER((TRACE_DEBUG,_F_,gSalts.bufPBKDF2KeySalt,PBKDF2_SALT_LEN,"gbufPBKDF2KeySalt")); rc=0; end: TRACE((TRACE_LEAVE,_F_, "rc=%d",rc)); return rc; }
//----------------------------------------------------------------------------- // swGenPBKDF2Salt() //----------------------------------------------------------------------------- // Génère deux sels aléatoires pour gbufPBKDF2PwdSalt et gbufPBKDF2KeySalt //----------------------------------------------------------------------------- int swGenPBKDF2Salt(void) { TRACE((TRACE_ENTER,_F_, "")); int rc=-1; BOOL brc; BYTE *pBuffer128Ko=NULL; // Pour être sûr d'avoir un aléa non attaquable, je suis la préco du §8.1.2 du document // "Cryptanalysis of the Windows Random Number Generator" de Leo Dorrendorf : // 1. Request and discard 128 kilobytes of WRNG output. // 2. Request as many bytes as needed to generate the secure token. // 3. Request and discard 128 kilobytes of WRNG output. // Remarque : c'est vraiment du luxe dans notre cas ! // 1. Request and discard 128 kilobytes of WRNG output. pBuffer128Ko=(BYTE*)malloc(DRAIN_BUFFER_SIZE); if (pBuffer128Ko==NULL) { TRACE((TRACE_ERROR,_F_,"malloc(%d)",128*1024)); goto end; } brc=CryptGenRandom(ghProv,DRAIN_BUFFER_SIZE,pBuffer128Ko); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGenRandom(DRAIN_BUFFER_SIZE)=0x%08lx",GetLastError())); goto end; } TRACE((TRACE_DEBUG,_F_,"CryptGenRandom(DRAIN_BUFFER_SIZE) 1/2")); SecureZeroMemory(pBuffer128Ko,DRAIN_BUFFER_SIZE); // 2. Request as many bytes as needed to generate the secure token. brc=CryptGenRandom(ghProv,PBKDF2_SALT_LEN,gSalts.bufPBKDF2PwdSalt); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGenRandom(gbufPBKDF2PwdSalt)=0x%08lx",GetLastError())); goto end; } brc=CryptGenRandom(ghProv,PBKDF2_SALT_LEN,gSalts.bufPBKDF2KeySalt); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGenRandom(gbufPBKDF2KeySalt)=0x%08lx",GetLastError())); goto end; } // 3. Request and discard 128 kilobytes of WRNG output. brc=CryptGenRandom(ghProv,DRAIN_BUFFER_SIZE,pBuffer128Ko); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGenRandom(DRAIN_BUFFER_SIZE)=0x%08lx",GetLastError())); goto end; } SecureZeroMemory(pBuffer128Ko,DRAIN_BUFFER_SIZE); TRACE((TRACE_DEBUG,_F_,"CryptGenRandom(DRAIN_BUFFER_SIZE) 2/2")); TRACE_BUFFER((TRACE_DEBUG,_F_,gSalts.bufPBKDF2PwdSalt,PBKDF2_SALT_LEN,"gSalts.bufPBKDF2PwdSalt")); TRACE_BUFFER((TRACE_DEBUG,_F_,gSalts.bufPBKDF2KeySalt,PBKDF2_SALT_LEN,"gSalts.bufPBKDF2KeySalt")); gSalts.bPBKDF2KeySaltReady=TRUE; gSalts.bPBKDF2PwdSaltReady=TRUE; rc=0; end: if (pBuffer128Ko!=NULL) free(pBuffer128Ko); TRACE((TRACE_LEAVE,_F_, "rc=%d",rc)); return rc; }
//----------------------------------------------------------------------------- // swCreateAESKeyFromKeyData() //----------------------------------------------------------------------------- // Crée la clé AES à partir de données de la clé (256 bits / 32 octets) // et l'importe dans le ghProv //----------------------------------------------------------------------------- // [in] cszMasterPwd = mot de passe maitre // [in/out] hKey = handle de clé //----------------------------------------------------------------------------- // Retour : 0 si OK //----------------------------------------------------------------------------- int swCreateAESKeyFromKeyData(BYTE *pAESKeyData,HCRYPTKEY *phKey) { int iAESKeySize; KEYBLOB *pAESKey=NULL; BOOL brc; int rc=-1; TRACE((TRACE_ENTER,_F_,"")); BYTE ZeroBuf[AES256_KEY_LEN]; // ZeroMemory(ZeroBuf,AES256_KEY_LEN); if (memcmp(pAESKeyData,ZeroBuf,AES256_KEY_LEN)==0) { TRACE((TRACE_ERROR,_F_,"pAESKeyData is zerobuf")); goto end; } // Crée la clé AES iAESKeySize=sizeof(KEYBLOB)+AES256_KEY_LEN; pAESKey=(KEYBLOB*)malloc(iAESKeySize); if (pAESKey==NULL) { TRACE((TRACE_ERROR,_F_,"malloc(%d)",iAESKeySize)); goto end; } ZeroMemory(pAESKey,iAESKeySize); pAESKey->header.bType=PLAINTEXTKEYBLOB; pAESKey->header.bVersion=CUR_BLOB_VERSION; pAESKey->header.reserved=0; pAESKey->header.aiKeyAlg=CALG_AES_256; pAESKey->dwKeySize=AES256_KEY_LEN; memcpy(pAESKey->KeyData,pAESKeyData,AES256_KEY_LEN); TRACE_BUFFER((TRACE_DEBUG,_F_,(BYTE*)pAESKey,iAESKeySize,"pAESKey (iAESKeySize=%d)",iAESKeySize)); brc= CryptImportKey(ghProv,(LPBYTE)pAESKey,iAESKeySize,NULL,0,phKey); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptImportKey()=0x%08lx",GetLastError())); goto end; } rc=0; end: if (pAESKey!=NULL) free(pAESKey); TRACE((TRACE_LEAVE,_F_,"rc=%d",rc)); return rc; }
static int stpg_event_loop(void) { int res = 0, status; int event_fd; uint8_t event_user_buf[1024*1024]; pid_t c_pid = 0; struct pollfd pl; struct scst_event_user *event_user = (struct scst_event_user *)event_user_buf; struct scst_event e1; bool first_error = true; event_fd = open(SCST_EVENT_DEV, O_RDWR); if (event_fd < 0) { res = -errno; PRINT_ERROR("Unable to open SCST event device %s (%s)", SCST_EVENT_DEV, strerror(-res)); goto out; } close(stpg_init_report_pipe[0]); if (log_daemon) res = write(stpg_init_report_pipe[1], &res, sizeof(res)); close(stpg_init_report_pipe[1]); memset(&pl, 0, sizeof(pl)); pl.fd = event_fd; pl.events = POLLIN; memset(&e1, 0, sizeof(e1)); e1.event_code = SCST_EVENT_STPG_USER_INVOKE; strncpy(e1.issuer_name, SCST_EVENT_SCST_CORE_ISSUER, sizeof(e1.issuer_name)); e1.issuer_name[sizeof(e1.issuer_name)-1] = '\0'; PRINT_INFO("Setting allowed event code %d, issuer_name %s", e1.event_code, e1.issuer_name); res = ioctl(event_fd, SCST_EVENT_ALLOW_EVENT, &e1); if (res != 0) { res = -errno; PRINT_ERROR("SCST_EVENT_ALLOW_EVENT failed: %d (%s)", res, strerror(-res)); goto out; } e1.event_code = SCST_EVENT_TM_FN_RECEIVED; strncpy(e1.issuer_name, SCST_EVENT_SCST_CORE_ISSUER, sizeof(e1.issuer_name)); e1.issuer_name[sizeof(e1.issuer_name)-1] = '\0'; PRINT_INFO("Setting allowed event code %d, issuer_name %s", e1.event_code, e1.issuer_name); res = ioctl(event_fd, SCST_EVENT_ALLOW_EVENT, &e1); if (res != 0) { res = -errno; PRINT_ERROR("SCST_EVENT_ALLOW_EVENT failed: %d (%s)", res, strerror(-res)); goto out; } while (1) { memset(event_user_buf, 0, sizeof(event_user_buf)); event_user->max_event_size = sizeof(event_user_buf); res = ioctl(event_fd, SCST_EVENT_GET_NEXT_EVENT, event_user); if (res != 0) { res = -errno; switch (-res) { case ESRCH: case EBUSY: TRACE_MGMT_DBG("SCST_EVENT_GET_NEXT_EVENT " "returned %d (%s)", res, strerror(res)); /* go through */ case EINTR: continue; case EAGAIN: TRACE_DBG("SCST_EVENT_GET_NEXT_EVENT, " "returned EAGAIN (%d)", -res); continue; default: PRINT_ERROR("SCST_EVENT_GET_NEXT_EVENT " "failed: %d (%s)", res, strerror(-res)); if (!first_error) goto out; first_error = false; continue; } first_error = true; again_poll: res = poll(&pl, 1, c_pid > 0 ? 1 : 0); if (res > 0) continue; else if (res == 0) goto again_poll; else { res = -errno; switch (res) { case ESRCH: case EBUSY: case EAGAIN: TRACE_MGMT_DBG("poll() returned %d " "(%s)", res, strerror(-res)); case EINTR: goto again_poll; default: PRINT_ERROR("poll() failed: %d (%s)", res, strerror(-res)); goto again_poll; } } } first_error = true; #ifdef DEBUG PRINT_INFO("event_code %d, issuer_name %s", event_user->out_event.event_code, event_user->out_event.issuer_name); #endif if (event_user->out_event.payload_len != 0) TRACE_BUFFER("payload", event_user->out_event.payload, event_user->out_event.payload_len); if (event_user->out_event.event_code == SCST_EVENT_STPG_USER_INVOKE) { c_pid = fork(); if (c_pid == -1) PRINT_ERROR("Failed to fork: %d", c_pid); else if (c_pid == 0) { struct scst_event_notify_done d; signal(SIGCHLD, SIG_DFL); status = handle_stpg_received(event_user); memset(&d, 0, sizeof(d)); d.event_id = event_user->out_event.event_id; d.status = status; res = ioctl(event_fd, SCST_EVENT_NOTIFY_DONE, &d); if (res != 0) { res = -errno; PRINT_ERROR("SCST_EVENT_NOTIFY_DONE " "failed: %s (res %d)", strerror(-res), res); } else PRINT_INFO("STPG event completed with status %d", status); exit(res); } } else if (event_user->out_event.event_code == SCST_EVENT_TM_FN_RECEIVED) stpg_handle_tm_received(event_user); else PRINT_ERROR("Unknown event %d received", event_user->out_event.event_code); } out: return res; }
void AudioProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness, bool realTimeEvent) { TRACE_BUFFER("%p->AudioProducer::HandleEvent()\n", this); switch (event->type) { case BTimedEventQueue::B_START: TRACE("AudioProducer::HandleEvent(B_START)\n"); if (RunState() != B_STARTED) { fFramesSent = 0; fStartTime = event->event_time + fSupplier->InitialLatency(); printf("B_START: start time: %lld\n", fStartTime); media_timed_event firstBufferEvent( fStartTime - fSupplier->InitialLatency(), BTimedEventQueue::B_HANDLE_BUFFER); EventQueue()->AddEvent(firstBufferEvent); } TRACE("AudioProducer::HandleEvent(B_START) done\n"); break; case BTimedEventQueue::B_STOP: TRACE("AudioProducer::HandleEvent(B_STOP)\n"); EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); TRACE("AudioProducer::HandleEvent(B_STOP) done\n"); break; case BTimedEventQueue::B_HANDLE_BUFFER: { TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER)\n"); if (RunState() == BMediaEventLooper::B_STARTED && fOutput.destination != media_destination::null) { BBuffer* buffer = _FillNextBuffer(event->event_time); if (buffer) { status_t err = B_ERROR; if (fOutputEnabled) { err = SendBuffer(buffer, fOutput.source, fOutput.destination); } if (err) buffer->Recycle(); } size_t sampleSize = fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; size_t nFrames = fOutput.format.u.raw_audio.buffer_size / (sampleSize * fOutput.format.u.raw_audio.channel_count); fFramesSent += nFrames; fNextScheduledBuffer = fStartTime + bigtime_t(double(fFramesSent) * 1000000.0 / double(fOutput.format.u.raw_audio.frame_rate)); media_timed_event nextBufferEvent(fNextScheduledBuffer, BTimedEventQueue::B_HANDLE_BUFFER); EventQueue()->AddEvent(nextBufferEvent); } else { ERROR("B_HANDLE_BUFFER, but not started!\n"); } TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER) done\n"); break; } default: break; } }
//----------------------------------------------------------------------------- // swCryptSaltAndHashPassword() // N'EST PLUS UTILISEE A PARTIR DE LA VERSION 0.93 ET PBKDF2 //----------------------------------------------------------------------------- // Sale et hashe le mot de passe maitre // si le buffer de sel est NULL, génération aléa (création, sinon c'est une vérif) // 0.72 : nouveau paramètre iNbIterations (nb d'itérations de hashage) // 0.73 : nouveau paramètre bV72 pour correction itération mal implémentée en 0.72 //----------------------------------------------------------------------------- int swCryptSaltAndHashPassword(char *bufSalt, const char *szPwd,char **pszHashedPwd,int iNbIterations,bool bV72) { TRACE((TRACE_ENTER,_F_,"bufSalt=0x%08lx",bufSalt)); int rc=-1; BOOL brc; HCRYPTHASH hHash=NULL; DWORD lenPwd; DWORD lenHashedPwd; unsigned char *bufSaltedPwd=NULL; DWORD lenSaltedPwd; unsigned char bufHash[HASH_LEN]; DWORD lenHash; // 0.73 unsigned char bufToHash[HASH_LEN]; lenPwd=strlen(szPwd); lenSaltedPwd=SALT_LEN+lenPwd; lenHashedPwd=SALT_LEN*2+HASH_LEN*2+1; int i; // allocation du buffer pour stocker le sel et le mot de passe // c'est ce buffer qu'on hache ensuite bufSaltedPwd=(unsigned char*)malloc(lenSaltedPwd); if (bufSaltedPwd==NULL) { TRACE((TRACE_ERROR,_F_,"malloc(%d)",lenSaltedPwd)); goto end; } if (bufSalt==NULL) // génère le sel { brc = CryptGenRandom(ghProv,SALT_LEN,bufSaltedPwd); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGenRandom()")); goto end; } } else // utilise le sel passé en paramètre { memcpy(bufSaltedPwd,bufSalt,SALT_LEN); } TRACE_BUFFER((TRACE_DEBUG,_F_,bufSaltedPwd,SALT_LEN,"sel")); // concatène le mot de passe memcpy(bufSaltedPwd+SALT_LEN,szPwd,lenPwd); //TRACE_BUFFER((TRACE_PWD,_F_,bufSaltedPwd,lenSaltedPwd,"à hacher")); // 0.72 (trace déplacée) // hashe le tout brc= CryptCreateHash(ghProv,CALG_SHA1,0,0,&hHash); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptCreateHash()")); goto end; } if (bV72) { // 0.72 : boucle hashage anti-cassage de mot de passe // foireux, j'ai oublié de réinjecter le hash... honte à moi // corrigé ci-dessous en 0.73 for (i=0;i<iNbIterations;i++) { brc = CryptHashData(hHash,bufSaltedPwd,lenSaltedPwd,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptHashData()")); goto end; } } // récupère la valeur du hash lenHash=sizeof(bufHash); brc = CryptGetHashParam(hHash,HP_HASHVAL,bufHash,&lenHash,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGetHashParam(HP_HASHVAL)")); goto end; } } else // version 073 corrige la 0.72... { // hashe le mot de passe brc = CryptHashData(hHash,bufSaltedPwd,lenSaltedPwd,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptHashData()")); goto end; } // récupère la valeur du hash lenHash=sizeof(bufHash); brc = CryptGetHashParam(hHash,HP_HASHVAL,bufHash,&lenHash,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGetHashParam(HP_HASHVAL)")); goto end; } CryptDestroyHash(hHash); hHash=NULL; // itérations = hash le hash iNbIterations fois. for (i=0;i<iNbIterations;i++) { // copie le résultat du hash dans le buffer à hasher pour itérer memcpy(bufToHash,bufHash,lenHash); brc= CryptCreateHash(ghProv,CALG_SHA1,0,0,&hHash); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptCreateHash()")); goto end; } // hashe le hash brc = CryptHashData(hHash,bufToHash,lenHash,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptHashData()")); goto end; } // récupère la valeur du hash lenHash=sizeof(bufHash); brc = CryptGetHashParam(hHash,HP_HASHVAL,bufHash,&lenHash,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGetHashParam(HP_HASHVAL)")); goto end; } CryptDestroyHash(hHash); hHash=NULL; } } TRACE_BUFFER((TRACE_DEBUG,_F_,bufHash,lenHash,"hash")); // il reste à convertir chaque morceau (sel et résultat du hash) en base 64 // et à concaténer les 2 // allocation de la destination *pszHashedPwd=(char*)malloc(lenHashedPwd); if (*pszHashedPwd==NULL) { TRACE((TRACE_ERROR,_F_,"malloc(%d)",lenHashedPwd)); goto end; } swCryptEncodeBase64(bufSaltedPwd,SALT_LEN,*pszHashedPwd); swCryptEncodeBase64(bufHash,HASH_LEN,*pszHashedPwd+SALT_LEN*2); TRACE((TRACE_DEBUG,_F_,"*pszHashedPwd=%s",*pszHashedPwd)); rc=0; end: if (bufSaltedPwd!=NULL) free(bufSaltedPwd); // 0.72 : libération du hash if (hHash!=NULL) CryptDestroyHash(hHash); TRACE((TRACE_LEAVE,_F_,"rc=%d",rc)); return rc; }
//----------------------------------------------------------------------------- // swPBKDF2() : implémentation de PBKDF2 RFC 2898 (http://www.ietf.org/rfc/rfc2898.txt) // Limitée à 2 blocs de 160 bits en sortie, dont seuls les 256 premiers sont // fournis à l'appelant. Ce résultat est utilisé pour : // 1) Alimenter la fonction de dérivation de clé AES-256 (CryptDeriveKey) // 2) Stocker le mot de passe maître //----------------------------------------------------------------------------- // Avec 2 blocs, l'algo proposé par la RFC donne : // DK = T_1 || T_2 // T_1 = F (P, S, c, 1) // T_2 = F (P, S, c, 2) // où : // P = password, an octet string // S = salt, an octet string // c = iteration count, a positive integer // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c // U_1 = PRF (P, S || INT (i)) // U_2 = PRF (P, U_1) // ... // U_c = PRF (P, U_{c-1}) //----------------------------------------------------------------------------- // MERCI A GUILLAUME POUR SA PROPOSITION D'IMPLEMENTATION ! //----------------------------------------------------------------------------- // [out]bufResult = pointeur vers un buffer de bytes (alloué par l'appelant) // [in] bufResultLen = taille de clé souhaitée (max HASH_LENx2) // [in] szPwd = mot de passe maitre a deriver // [in] bufSalt = buffer contenant le sel // [in] bufSaltLen = taille du buffer de sel (PBKDF2_SALT_LEN) // [in] iNbIterations = nombre d'itérations //----------------------------------------------------------------------------- int swPBKDF2(BYTE *bufResult,int bufResultLen,const char *szPwd,const BYTE *bufSalt,int bufSaltLen,int iNbIterations) { TRACE((TRACE_ENTER,_F_,"bufResultLen=%d iNbIterations=%d",bufResultLen,iNbIterations)); //TRACE((TRACE_PWD,_F_,"szPwd=%s",szPwd)); TRACE_BUFFER((TRACE_DEBUG,_F_,(BYTE*)bufSalt,bufSaltLen,"sel")); int brc; int c; // itérations int rc=-1; HCRYPTKEY hKey=NULL; HCRYPTHASH hHMAC=NULL; HMAC_INFO hmacinfo; KEYBLOB *pKey=NULL; int iKeySize; DWORD dwLenHash; BYTE bufU_c[HASH_LEN]; // stocke successivement U_1, U_2, ..., U_c BYTE bufT[HASH_LEN*2]; // stocke le résultat final : T_1 à l'index 0 et T_2 à l'index HASH_LEN BYTE bufSaltWithBlocIndex[PBKDF2_SALT_LEN+4]; int iBloc; if (bufResultLen>HASH_LEN*2) { TRACE((TRACE_ERROR,_F_,"bufResultLen=%d > valeur autorisée HASH_LEN*2=%d",bufResultLen,HASH_LEN*2)); goto end; } if (bufSaltLen!=PBKDF2_SALT_LEN) { TRACE((TRACE_ERROR,_F_,"bufSaltLen=%d != valeur imposée PBKDF2_SALT_LEN=%d",bufSaltLen,PBKDF2_SALT_LEN)); goto end; } // Création de la clé HMAC en mode PLAINTEXTKEYBLOB, à partir du mot de passe iKeySize=sizeof(KEYBLOB)+strlen(szPwd); pKey=(KEYBLOB*)malloc(iKeySize); if (pKey==NULL) { TRACE((TRACE_ERROR,_F_,"malloc(%d)",iKeySize)); goto end; } ZeroMemory(pKey,iKeySize); // Création de la clé symétrique pour le HMAC // cf. doc de CryptImportKey() -> http://msdn.microsoft.com/en-us/library/aa380207(v=vs.85).aspx : // "When importing a Hash-Based Message Authentication Code (HMAC) key, the caller must identify // the imported key as a PLAINTEXTKEYBLOB type" // "The HMAC algorithms do not have their own algorithm identifiers; use CALG_RC2 instead. // CRYPT_IPSEC_HMAC_KEY allows the import of RC2 keys longer than 16 bytes." // cf. tests vectors de la RFC 2202 HMAC-SHA1 pKey->header.bType=PLAINTEXTKEYBLOB; pKey->header.bVersion=CUR_BLOB_VERSION; pKey->header.reserved=0; pKey->header.aiKeyAlg=CALG_RC2; pKey->dwKeySize=strlen(szPwd); memcpy(pKey->KeyData,szPwd,pKey->dwKeySize); // test case 1 RFC 2202 HMAC-SHA1 /*pKey->dwKeySize=20; memset(pKey->KeyData,0x0b,pKey->dwKeySize);*/ // fin test case 1 RFC 2202 HMAC-SHA1 // test case 7 RFC 2202 HMAC-SHA1 /*pKey->dwKeySize=80; memset(pKey->KeyData,0xaa,pKey->dwKeySize);*/ // fin test case 7 RFC 2202 HMAC-SHA1 //TRACE_BUFFER((TRACE_PWD,_F_,(BYTE*)pKey,iKeySize,"pKey (iKeySize=%d)",iKeySize)); brc= CryptImportKey(ghProv,(LPBYTE)pKey,iKeySize,NULL,CRYPT_IPSEC_HMAC_KEY,&hKey); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptImportKey()=0x%08lx",GetLastError())); goto end; } // Initialisation du buffer resultat a zero ZeroMemory(bufT,HASH_LEN*2); // Itération pour sortir 2 blocs de 160 bits chacun (T_1 et T_2) for (iBloc=1;iBloc<=2;iBloc++) { // concaténation de l'index de bloc au sel memcpy(bufSaltWithBlocIndex,bufSalt,PBKDF2_SALT_LEN); bufSaltWithBlocIndex[bufSaltLen]=0x00; bufSaltWithBlocIndex[bufSaltLen+1]=0x00; bufSaltWithBlocIndex[bufSaltLen+2]=0x00; bufSaltWithBlocIndex[bufSaltLen+3]=(BYTE)iBloc; TRACE_BUFFER((TRACE_DEBUG,_F_,bufSaltWithBlocIndex,bufSaltLen+4,"bufSaltWithBlocIndex")); // Création du HMAC // cf. http://msdn.microsoft.com/en-us/library/aa382379(VS.85).aspx brc=CryptCreateHash(ghProv,CALG_HMAC,hKey,0,&hHMAC); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptCreateHash()=0x%08lx",GetLastError())); goto end; } // Initialisation des paramètres du HMAC ZeroMemory(&hmacinfo,sizeof(hmacinfo)); hmacinfo.HashAlgid=CALG_SHA1; brc=CryptSetHashParam(hHMAC,HP_HMAC_INFO, (BYTE*)&hmacinfo,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptSetHashParam()=0x%08lx",GetLastError())); goto end; } // test case 1 RFC 2202 HMAC-SHA1 /*brc=CryptHashData(hHMAC,(const BYTE*)"Hi There",8, 0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptCreateHash()=0x%08lx",GetLastError())); goto end; } brc=CryptGetHashParam(hHMAC,HP_HASHVAL,bufU_c,&dwLenHash,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGetHashParam()=0x%08lx",GetLastError())); goto end; } TRACE_BUFFER((TRACE_DEBUG,_F_,bufU_c,HASH_LEN,"Test case 1 RFC 2202 HMAC-SHA1")); if (brc) goto end;*/ // fin test case 1 RFC 2202 HMAC-SHA1 // test case 7 RFC 2202 HMAC-SHA1 /*brc=CryptHashData(hHMAC,(const BYTE*)"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",73, 0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptCreateHash()=0x%08lx",GetLastError())); goto end; } brc=CryptGetHashParam(hHMAC,HP_HASHVAL,bufU_c,&dwLenHash,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGetHashParam()=0x%08lx",GetLastError())); goto end; } TRACE_BUFFER((TRACE_DEBUG,_F_,bufU_c,HASH_LEN,"Test case 1 RFC 2202 HMAC-SHA1")); if (brc) goto end;*/ // fin test case 7 RFC 2202 HMAC-SHA1 // HMAC du sel enrichi de l'id de bloc brc=CryptHashData(hHMAC,bufSaltWithBlocIndex,bufSaltLen+4, 0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptHashData(bufSaltWithBlocIndex)=0x%08lx",GetLastError())); goto end; } // Récupération du hash dwLenHash=sizeof(bufU_c); brc=CryptGetHashParam(hHMAC,HP_HASHVAL,bufU_c,&dwLenHash,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGetHashParam(bufU_1)=0x%08lx",GetLastError())); goto end; } TRACE_BUFFER((TRACE_DEBUG,_F_,bufU_c,HASH_LEN,"bufU_1")); // Destruction du HMAC brc=CryptDestroyHash(hHMAC); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptDestroyHash()=0x%08lx",GetLastError())); goto end; } hHMAC=NULL; // XOR dans le buffer résultat swXORBuff(bufT+(iBloc-1)*HASH_LEN,bufU_c,HASH_LEN); // Iterations for (c=2;c<=iNbIterations;c++) // on démarre à 1, la 1ère itération étant faite précédemment hors de la boucle { // Création du HMAC brc=CryptCreateHash(ghProv,CALG_HMAC,hKey,0,&hHMAC); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptCreateHash()=0x%08lx",GetLastError())); goto end; } // Initialisation des paramètres du HMAC ZeroMemory(&hmacinfo,sizeof(hmacinfo)); hmacinfo.HashAlgid=CALG_SHA1; brc=CryptSetHashParam(hHMAC,HP_HMAC_INFO,(BYTE*)&hmacinfo,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptSetHashParam()=0x%08lx",GetLastError())); goto end; } // HMAC du résultat de l'itération précédente brc=CryptHashData(hHMAC,bufU_c,HASH_LEN,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptHashData(bufU_%d)=0x%08lx",c,GetLastError())); goto end; } // Recup du hash brc=CryptGetHashParam(hHMAC,HP_HASHVAL,bufU_c,&dwLenHash,0); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptGetHashParam(bufU_%d)=0x%08lx",c,GetLastError())); goto end; } // Détruire le HMAC brc=CryptDestroyHash(hHMAC); if (!brc) { TRACE((TRACE_ERROR,_F_,"CryptDestroyHash()=0x%08lx",GetLastError())); goto end; } hHMAC=NULL; // XOR dans le resultat swXORBuff(bufT+(iBloc-1)*HASH_LEN,bufU_c,HASH_LEN); } TRACE_BUFFER((TRACE_DEBUG,_F_,bufT+(iBloc-1)*HASH_LEN,HASH_LEN,"bufT_%d",iBloc)); } // Les 2 blocs sont alimentés, on extrait les bufResultLen pour alimenter bufResult memcpy(bufResult,bufT,bufResultLen); TRACE_BUFFER((TRACE_DEBUG,_F_,bufResult,bufResultLen,"bufResult")); rc=0; end: if (hHMAC!=NULL) CryptDestroyHash(hHMAC); if (hKey!=NULL) CryptDestroyKey(hKey); if (pKey!=NULL) free(pKey); TRACE((TRACE_LEAVE,_F_,"rc=%d",rc)); return rc; }