summaryrefslogtreecommitdiff
path: root/src/mongo/crypto/mechanism_scram.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/crypto/mechanism_scram.cpp')
-rw-r--r--src/mongo/crypto/mechanism_scram.cpp388
1 files changed, 184 insertions, 204 deletions
diff --git a/src/mongo/crypto/mechanism_scram.cpp b/src/mongo/crypto/mechanism_scram.cpp
index 39695ca4bac..8ec28b3e2c6 100644
--- a/src/mongo/crypto/mechanism_scram.cpp
+++ b/src/mongo/crypto/mechanism_scram.cpp
@@ -39,211 +39,191 @@
namespace mongo {
namespace scram {
- using std::unique_ptr;
-
- // Compute the SCRAM step Hi() as defined in RFC5802
- static void HMACIteration(const unsigned char input[],
- size_t inputLen,
- const unsigned char salt[],
- size_t saltLen,
- unsigned int iterationCount,
- unsigned char output[]){
- unsigned char intermediateDigest[hashSize];
- unsigned char startKey[hashSize];
- // Placeholder for HMAC return size, will always be scram::hashSize for HMAC SHA-1
- unsigned int hashLen = 0;
-
- uassert(17450, "invalid salt length provided", saltLen + 4 == hashSize);
- memcpy (startKey, salt, saltLen);
-
- startKey[saltLen] = 0;
- startKey[saltLen+1] = 0;
- startKey[saltLen+2] = 0;
- startKey[saltLen+3] = 1;
-
- // U1 = HMAC(input, salt + 0001)
- fassert(17494, crypto::hmacSha1(input,
- inputLen,
- startKey,
- saltLen + 4,
- output,
- &hashLen));
-
- memcpy(intermediateDigest, output, hashSize);
-
- // intermediateDigest contains Ui and output contains the accumulated XOR:ed result
- for (size_t i = 2; i <= iterationCount; i++) {
- unsigned char intermediateOutput[hashSize];
- fassert(17495, crypto::hmacSha1(input,
- inputLen,
- intermediateDigest,
- hashSize,
- intermediateOutput,
- &hashLen));
- memcpy(intermediateDigest, intermediateOutput, hashSize);
- for (size_t k = 0; k < hashSize; k++) {
- output[k] ^= intermediateDigest[k];
- }
+using std::unique_ptr;
+
+// Compute the SCRAM step Hi() as defined in RFC5802
+static void HMACIteration(const unsigned char input[],
+ size_t inputLen,
+ const unsigned char salt[],
+ size_t saltLen,
+ unsigned int iterationCount,
+ unsigned char output[]) {
+ unsigned char intermediateDigest[hashSize];
+ unsigned char startKey[hashSize];
+ // Placeholder for HMAC return size, will always be scram::hashSize for HMAC SHA-1
+ unsigned int hashLen = 0;
+
+ uassert(17450, "invalid salt length provided", saltLen + 4 == hashSize);
+ memcpy(startKey, salt, saltLen);
+
+ startKey[saltLen] = 0;
+ startKey[saltLen + 1] = 0;
+ startKey[saltLen + 2] = 0;
+ startKey[saltLen + 3] = 1;
+
+ // U1 = HMAC(input, salt + 0001)
+ fassert(17494, crypto::hmacSha1(input, inputLen, startKey, saltLen + 4, output, &hashLen));
+
+ memcpy(intermediateDigest, output, hashSize);
+
+ // intermediateDigest contains Ui and output contains the accumulated XOR:ed result
+ for (size_t i = 2; i <= iterationCount; i++) {
+ unsigned char intermediateOutput[hashSize];
+ fassert(17495,
+ crypto::hmacSha1(
+ input, inputLen, intermediateDigest, hashSize, intermediateOutput, &hashLen));
+ memcpy(intermediateDigest, intermediateOutput, hashSize);
+ for (size_t k = 0; k < hashSize; k++) {
+ output[k] ^= intermediateDigest[k];
}
}
-
- // Iterate the hash function to generate SaltedPassword
- void generateSaltedPassword(StringData hashedPassword,
- const unsigned char* salt,
- const int saltLen,
- const int iterationCount,
- unsigned char saltedPassword[hashSize]) {
- // saltedPassword = Hi(hashedPassword, salt)
- HMACIteration(reinterpret_cast<const unsigned char*>(hashedPassword.rawData()),
- hashedPassword.size(),
- salt,
- saltLen,
- iterationCount,
- saltedPassword);
- }
-
- void generateSecrets(const std::string& hashedPassword,
- const unsigned char salt[],
- size_t saltLen,
- size_t iterationCount,
- unsigned char storedKey[hashSize],
- unsigned char serverKey[hashSize]) {
-
- unsigned char saltedPassword[hashSize];
- unsigned char clientKey[hashSize];
- unsigned int hashLen = 0;
-
- generateSaltedPassword(hashedPassword,
- salt,
- saltLen,
- iterationCount,
- saltedPassword);
-
- // clientKey = HMAC(saltedPassword, "Client Key")
- fassert(17498,
- crypto::hmacSha1(saltedPassword,
- hashSize,
- reinterpret_cast<const unsigned char*>(clientKeyConst.data()),
- clientKeyConst.size(),
- clientKey,
- &hashLen));
-
- // storedKey = H(clientKey)
- fassert(17499, crypto::sha1(clientKey, hashSize, storedKey));
-
- // serverKey = HMAC(saltedPassword, "Server Key")
- fassert(17500,
- crypto::hmacSha1(saltedPassword,
- hashSize,
- reinterpret_cast<const unsigned char*>(serverKeyConst.data()),
- serverKeyConst.size(),
- serverKey,
- &hashLen));
- }
-
- BSONObj generateCredentials(const std::string& hashedPassword, int iterationCount) {
-
- const int saltLenQWords = 2;
-
- // Generate salt
- uint64_t userSalt[saltLenQWords];
-
- unique_ptr<SecureRandom> sr(SecureRandom::create());
-
- userSalt[0] = sr->nextInt64();
- userSalt[1] = sr->nextInt64();
- std::string encodedUserSalt =
- base64::encode(reinterpret_cast<char*>(userSalt), sizeof(userSalt));
-
- // Compute SCRAM secrets serverKey and storedKey
- unsigned char storedKey[hashSize];
- unsigned char serverKey[hashSize];
-
- generateSecrets(hashedPassword,
- reinterpret_cast<unsigned char*>(userSalt),
- saltLenQWords*sizeof(uint64_t),
- iterationCount,
- storedKey,
- serverKey);
-
- std::string encodedStoredKey =
- base64::encode(reinterpret_cast<char*>(storedKey), hashSize);
- std::string encodedServerKey =
- base64::encode(reinterpret_cast<char*>(serverKey), hashSize);
-
- return BSON(iterationCountFieldName << iterationCount <<
- saltFieldName << encodedUserSalt <<
- storedKeyFieldName << encodedStoredKey <<
- serverKeyFieldName << encodedServerKey);
- }
-
- std::string generateClientProof(const unsigned char saltedPassword[hashSize],
- const std::string& authMessage) {
-
- // ClientKey := HMAC(saltedPassword, "Client Key")
- unsigned char clientKey[hashSize];
- unsigned int hashLen = 0;
- fassert(18689,
- crypto::hmacSha1(saltedPassword,
- hashSize,
- reinterpret_cast<const unsigned char*>(clientKeyConst.data()),
- clientKeyConst.size(),
- clientKey,
- &hashLen));
-
- // StoredKey := H(clientKey)
- unsigned char storedKey[hashSize];
- fassert(18701, crypto::sha1(clientKey, hashSize, storedKey));
-
- // ClientSignature := HMAC(StoredKey, AuthMessage)
- unsigned char clientSignature[hashSize];
- fassert(18702,
- crypto::hmacSha1(storedKey,
- hashSize,
- reinterpret_cast<const unsigned char*>(authMessage.c_str()),
- authMessage.size(),
- clientSignature,
- &hashLen));
-
- // ClientProof := ClientKey XOR ClientSignature
- unsigned char clientProof[hashSize];
- for (size_t i = 0; i<hashSize; i++) {
- clientProof[i] = clientKey[i] ^ clientSignature[i];
- }
-
- return base64::encode(reinterpret_cast<char*>(clientProof), hashSize);
-
- }
-
- bool verifyServerSignature(const unsigned char saltedPassword[hashSize],
- const std::string& authMessage,
- const std::string& receivedServerSignature) {
-
- // ServerKey := HMAC(SaltedPassword, "Server Key")
- unsigned int hashLen;
- unsigned char serverKey[hashSize];
- fassert(18703,
- crypto::hmacSha1(saltedPassword,
- hashSize,
- reinterpret_cast<const unsigned char*>(serverKeyConst.data()),
- serverKeyConst.size(),
- serverKey,
- &hashLen));
-
- // ServerSignature := HMAC(ServerKey, AuthMessage)
- unsigned char serverSignature[hashSize];
- fassert(18704,
- crypto::hmacSha1(serverKey,
- hashSize,
- reinterpret_cast<const unsigned char*>(authMessage.c_str()),
- authMessage.size(),
- serverSignature,
- &hashLen));
-
- std::string encodedServerSignature =
- base64::encode(reinterpret_cast<char*>(serverSignature), sizeof(serverSignature));
- return (receivedServerSignature == encodedServerSignature);
+}
+
+// Iterate the hash function to generate SaltedPassword
+void generateSaltedPassword(StringData hashedPassword,
+ const unsigned char* salt,
+ const int saltLen,
+ const int iterationCount,
+ unsigned char saltedPassword[hashSize]) {
+ // saltedPassword = Hi(hashedPassword, salt)
+ HMACIteration(reinterpret_cast<const unsigned char*>(hashedPassword.rawData()),
+ hashedPassword.size(),
+ salt,
+ saltLen,
+ iterationCount,
+ saltedPassword);
+}
+
+void generateSecrets(const std::string& hashedPassword,
+ const unsigned char salt[],
+ size_t saltLen,
+ size_t iterationCount,
+ unsigned char storedKey[hashSize],
+ unsigned char serverKey[hashSize]) {
+ unsigned char saltedPassword[hashSize];
+ unsigned char clientKey[hashSize];
+ unsigned int hashLen = 0;
+
+ generateSaltedPassword(hashedPassword, salt, saltLen, iterationCount, saltedPassword);
+
+ // clientKey = HMAC(saltedPassword, "Client Key")
+ fassert(17498,
+ crypto::hmacSha1(saltedPassword,
+ hashSize,
+ reinterpret_cast<const unsigned char*>(clientKeyConst.data()),
+ clientKeyConst.size(),
+ clientKey,
+ &hashLen));
+
+ // storedKey = H(clientKey)
+ fassert(17499, crypto::sha1(clientKey, hashSize, storedKey));
+
+ // serverKey = HMAC(saltedPassword, "Server Key")
+ fassert(17500,
+ crypto::hmacSha1(saltedPassword,
+ hashSize,
+ reinterpret_cast<const unsigned char*>(serverKeyConst.data()),
+ serverKeyConst.size(),
+ serverKey,
+ &hashLen));
+}
+
+BSONObj generateCredentials(const std::string& hashedPassword, int iterationCount) {
+ const int saltLenQWords = 2;
+
+ // Generate salt
+ uint64_t userSalt[saltLenQWords];
+
+ unique_ptr<SecureRandom> sr(SecureRandom::create());
+
+ userSalt[0] = sr->nextInt64();
+ userSalt[1] = sr->nextInt64();
+ std::string encodedUserSalt =
+ base64::encode(reinterpret_cast<char*>(userSalt), sizeof(userSalt));
+
+ // Compute SCRAM secrets serverKey and storedKey
+ unsigned char storedKey[hashSize];
+ unsigned char serverKey[hashSize];
+
+ generateSecrets(hashedPassword,
+ reinterpret_cast<unsigned char*>(userSalt),
+ saltLenQWords * sizeof(uint64_t),
+ iterationCount,
+ storedKey,
+ serverKey);
+
+ std::string encodedStoredKey = base64::encode(reinterpret_cast<char*>(storedKey), hashSize);
+ std::string encodedServerKey = base64::encode(reinterpret_cast<char*>(serverKey), hashSize);
+
+ return BSON(iterationCountFieldName << iterationCount << saltFieldName << encodedUserSalt
+ << storedKeyFieldName << encodedStoredKey
+ << serverKeyFieldName << encodedServerKey);
+}
+
+std::string generateClientProof(const unsigned char saltedPassword[hashSize],
+ const std::string& authMessage) {
+ // ClientKey := HMAC(saltedPassword, "Client Key")
+ unsigned char clientKey[hashSize];
+ unsigned int hashLen = 0;
+ fassert(18689,
+ crypto::hmacSha1(saltedPassword,
+ hashSize,
+ reinterpret_cast<const unsigned char*>(clientKeyConst.data()),
+ clientKeyConst.size(),
+ clientKey,
+ &hashLen));
+
+ // StoredKey := H(clientKey)
+ unsigned char storedKey[hashSize];
+ fassert(18701, crypto::sha1(clientKey, hashSize, storedKey));
+
+ // ClientSignature := HMAC(StoredKey, AuthMessage)
+ unsigned char clientSignature[hashSize];
+ fassert(18702,
+ crypto::hmacSha1(storedKey,
+ hashSize,
+ reinterpret_cast<const unsigned char*>(authMessage.c_str()),
+ authMessage.size(),
+ clientSignature,
+ &hashLen));
+
+ // ClientProof := ClientKey XOR ClientSignature
+ unsigned char clientProof[hashSize];
+ for (size_t i = 0; i < hashSize; i++) {
+ clientProof[i] = clientKey[i] ^ clientSignature[i];
}
-} // namespace scram
-} // namespace mongo
+ return base64::encode(reinterpret_cast<char*>(clientProof), hashSize);
+}
+
+bool verifyServerSignature(const unsigned char saltedPassword[hashSize],
+ const std::string& authMessage,
+ const std::string& receivedServerSignature) {
+ // ServerKey := HMAC(SaltedPassword, "Server Key")
+ unsigned int hashLen;
+ unsigned char serverKey[hashSize];
+ fassert(18703,
+ crypto::hmacSha1(saltedPassword,
+ hashSize,
+ reinterpret_cast<const unsigned char*>(serverKeyConst.data()),
+ serverKeyConst.size(),
+ serverKey,
+ &hashLen));
+
+ // ServerSignature := HMAC(ServerKey, AuthMessage)
+ unsigned char serverSignature[hashSize];
+ fassert(18704,
+ crypto::hmacSha1(serverKey,
+ hashSize,
+ reinterpret_cast<const unsigned char*>(authMessage.c_str()),
+ authMessage.size(),
+ serverSignature,
+ &hashLen));
+
+ std::string encodedServerSignature =
+ base64::encode(reinterpret_cast<char*>(serverSignature), sizeof(serverSignature));
+ return (receivedServerSignature == encodedServerSignature);
+}
+
+} // namespace scram
+} // namespace mongo