Beispiel #1
0
//-----------------------------------------------------------------------------
// 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;
}
Beispiel #2
0
//-----------------------------------------------------------------------------
// 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;
}
Beispiel #3
0
//-----------------------------------------------------------------------------
// 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;
}
Beispiel #4
0
//-----------------------------------------------------------------------------
// 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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
	}
}
Beispiel #7
0
//-----------------------------------------------------------------------------
// 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;
}
Beispiel #8
0
//-----------------------------------------------------------------------------
// 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;
}