130 likes | 299 Views
OTP-CryptoAPI. Gareth Richards, RSA Security OTPS Workshop , 17 October 2005. Overview. Describes general Microsoft CryptoAPI objects, procedures and mechanisms that can be used to retrieve OTPs
E N D
OTP-CryptoAPI Gareth Richards, RSA Security OTPS Workshop, 17 October 2005
Overview • Describes general Microsoft CryptoAPI objects, procedures and mechanisms that can be used to retrieve OTPs • Intended to meet the needs of applications wishing to access connected OTP tokens in an interoperable manner • Eases the task for vendors of OTP-consuming applications • Enables a better user experience • Intended to mirror the sister PKCS#11 document
CryptoAPI Principles of Operation • Intent is to follow the HMAC approach for CryptoAPI • CryptAcquireContext gives handle to key container • OTP algorithm given by key in the container • CryptCreateHash gives handle to OTP hash object • CryptSetHashParam sets the OTP parameters • CryptHashData generates OTPs • CryptGetHashParam retrieves the OTP value CryptAcquireContext CryptCreateHash CryptSetHashParam CryptHashData CryptGetHashParam
Basic Design • Cryptographic Service Providers supporting the described algorithms are identified as being of type PROV_OTP • OTP values generated through keyed hash objects of type CALG_OTP • Algorithm to use in OTP algorithm given by key type. • All OTP algorithms will be of type ALG_TYPE_OTP
Recent Modifications • Draft 2, published June 27 • Removed dependence on OTPS-P11 structures • Removed need for application to have algorithm specific knowledge • Draft 3, published August 17 • Changed OTP algorithms to use ALG_TYPE_OTP rather than ALG_CLASS_OTP • Allowed keys to be exported as a PLAINTEXTBLOB • Clarified use of KP_ALGID when importing or generating OTP keys • Added KP_OTP_LENGTH_MIN and KP_OTP_LENGTH_MAX • Redefinition of OTP flag values to match corresponding OTP-PKCS#11 values.
Recent Modifications – Continued • Draft 4, published September 27 • Renamed AT_OTP to AT_SHAREDSECRET per mailing list discussion. • Removed PP_OTP_PINPAD • Added PP_OTP_SERIAL_NUMBER provider parameter to contain the serial number of the device. • Added the KP_OTP USER_FRIENDLY_MODE to allow a provider to indicate if a key can support the generation of OTPs intended for human consumption. • Added CRYPT_OTP_FORMAT_BINARY to support tokens mainly intended for connected use • Added the CRYPT_OTP_USER_FRIENDLY flag to allow an application to request the user friendly format OTP. • Renamed CRYPT_OTP_VALUE_* and CRYPT_OTP_NO_* be consistent with the PKCS#11 document. • Clarified the default values for the OTP key parameters. • Removed the KP_OTP_LENGTH_MIN and the KP_OTP_LENGTH_MAX key parameters.
OTP Keys • Current draft defines two OTP algorithms • CALG_SECURID • CALG_HOTP • Key container can contain multiple keys • Default key can optionally identified by key type AT_SHAREDSECRET • Key properties given by key parameters • Default values • Algorithm requirements (e.g. PIN, Counter) • General information • Created through CryptGenKey and CryptSetKeyParam. • Imported through CryptImportKey and CryptSetKeyParam. • Finalized by setting KP_ALGID.
OTP Hash Objects • All OTP values are created as a keyed hash using a CALG_OTP hash object • OTP algorithm is given by the key used. • Default is to use AT_SHAREDSECRET key of the container • OTP calculation parameters are: • Passed as hash parameter HP_OTP_PARAMS • Controlled by KP_OTP_*_REQUIREMENTS parameters of the key • Values used returned in HP_OTP_PARAMS • OTP calculated using CryptHashData
Next Steps • Agreement and stabilization of document content • Preferably final draft within next 3 – 4 weeks, reflecting workshop discussions • Possible future contribution of document? • Would preferably be “adopted” by Microsoft • Need Microsoft recognition of at least: PROV_OTP, ALG_TYPE_OTP and AT_SHAREDSECRET • Preferably also the parameters and algorithm identifiers • Ideally, definitions and structures would be part of CRYPTOAPI.H • Submit document to Microsoft moderated CryptoAPI mailing list • What about new Windows Vista Crypto Next Generation (CNG)?
Importing an OTP Key HCRYPTPROV hProv = (HCRYPTPROV)NULL; HCRYPTKEY hOTPKey = (HCRYPTKEY)NULL; HCRYPTKEY hUnwrapKey = (HCRYPTKEY)NULL; BYTE blob[] = "..."; // SIMPLEBLOB or PLAINTEXTBLOB DWORD blobLen = sizeof(blob); ALG_ID algID = CALG_HOTP; DWORD counterRequirement = CRYPT_OTP_PARAM_OPTIONAL; BYTE keyID[] = "..."; DWORD keyIDLen = sizeof(keyID); CRYPT_DATA_BLOB keyIDBlob = {0, 0}; SYSTEMTIME expiryDate; CryptAcquireContext(&hProv, NULL, NULL, PROV_OTP, 0); CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hUnwrapKey); // Import the OTP key. CryptImportKey(hProv, blob, blobLen, hUnwrapKey, 0, &hOTPKey); // Set the key attributes keyIDBlob.cbData = keyIDLen; keyIDBlob.pbData = keyID; CryptSetKeyParam(hOTPKey, KP_OTP_ID, (BYTE *)&keyIDBlob, 0); CryptSetKeyParam(hOTPKey, KP_OTP_END_DATE, (BYTE *)&expiryDate, 0); CryptSetKeyParam(hOTPKey, KP_OTP_COUNTER_REQUIREMENT, (BYTE *)&counterRequirement, 0); // Enable the key. CryptSetKeyParam(hOTPKey, KP_ALGID, (BYTE *)&algID, 0); CryptDestroyKey(hUnwrapKey); CryptReleaseContext(hProv, 0);
Exporting an OTP Key BOOL ExportHOTPKey( HCRYPTKEY hOTPKey HCRTYPKEY hwrapKey, BYTE *blob, // Buffer to receive SIMPLEBLOB DWORD *blobLen { return CryptExportKey(hOTPKey, hWrapKey, SIMPLEBLOB, 0, blob, blobLen); }
Retrieving an OTP HCRYPTPROV hProv = (HCRYPTPROV)NULL; HCRYPTHASH hHash = (HCRYPTHASH)NULL; HCRYPTKEY hKey = (HCRYPTKEY)NULL; DWORD req; DWORD reqLen = sizeof(req); CHAR *pPIN = "..."; BYTE challenge[] = "..."; BYTE counter[] = "..."; SYSTEMTIME time; DWORD len = 0; DWORD OTPLen = 0; BYTE *pbOTP = NULL; int i = 0; OTP_PARAMETER param[4]; OTP_PARAMETERS otpParams; CryptAcquireContext(&hProv, NULL, NULL, PROV_OTP, 0); /* Acquire context to default OTP container of default provider */ CryptGetUserKey(hProv, AT_SHAREDSECRET, &hKey); /* Retrieve handle to default OTP key. */ CryptCreateHash(hProv, CALG_OTP, hKey, 0, &hHash); /* Create OTP hash object */ /* Determine the OTP requirements. */ i = 0; /* PIN */ CryptGetKeyParam(hKey, KP_OTP_PIN_REQUIREMENT, (BYTE *)&req, &reqLen, 0); if (req == CRYPT_OTP_PARAM_MANDATORY) { param[i].paramID = CRYPT_OTP_PIN; param[i].paramValue.cbData = lstrlen(pPIN); param[i].paramValue.pbData = (BYTE *)pPIN; } /* Challenge */ CryptGetKeyParam(hKey, KP_OTP_CHALLENGE_REQUIREMENT, (BYTE *)&req, &reqLen, 0); if (req == CRYPT_OTP_PARAM_MANDATORY) { param[i].paramID = CRYPT_OTP_CHALLENGE; param[i].paramValue.cbData = sizeof(challenge); param[i].paramValue.pbData = challenge; } /* Do the same for time and challenge */
Retrieving an OTP - Continued /* Set the OTP Parameters. */ if (i > 0) { otpParams.cParams = i; otpParams.pParams = param; CryptSetHashParam(hHash, HP_OTP_PARAMS, (const BYTE *)&otpParams, 0); } /* Generate the OTP. */ CryptHashData(hHash, NULL, 0, 0); /* Retrieve the length of the OTP */ len = sizeof(OTPLen); CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&OTPLen, &len, 0); /* Retrieve the OTP */ pbOTP = (BYTE*)malloc(OTPLen); len = OTPLen; CryptGetHashParam(hHash, HP_HASHVAL, pbOTP, &len, 0); /* Clean up */ CryptDestroyHash(hHash); CryptDestroyKey(hKey); CryptReleaseContext(hProv, 0); free(pbOTP);