예제 #1
0
        private void CreateInternal()
        {
            // Create Id
            var randomBytes = new byte[IdPartLengthBytes];

            using (var rng = new RNGCryptoServiceProvider())
            {
                rng.GetNonZeroBytes(randomBytes);
            }

            byte[] idBytes = new byte[IdPartLengthBytes + IdPrefix.Length];
            Buffer.BlockCopy(src: IdPrefix, srcOffset: 0, dst: idBytes, dstOffset: 0, count: IdPrefix.Length);
            Buffer.BlockCopy(src: randomBytes, srcOffset: 0, dst: idBytes, dstOffset: IdPrefix.Length, count: randomBytes.Length);

            // Convert to Base32 string. The length of the string is APIKeyV4_IdPartBase64Length
            string idString = idBytes.ToBase32String().RemoveBase32Padding();

            // Create password
            var passwordString = Guid.NewGuid().ToByteArray().ToBase32String().RemoveBase32Padding();

            passwordString = Normalize(passwordString);

            // No need to remove padding or normalize here.. it's stored in the DB and doesn't need to be pretty
            var hashedPasswordString = V3Hasher.GenerateHashAsBytes(passwordString).ToBase32String();

            IdPart          = Normalize(idString);
            PasswordPart    = passwordString;
            PlaintextApiKey = IdPart + passwordString;
            HashedApiKey    = IdPart + hashedPasswordString;
        }
예제 #2
0
        /// <summary>
        /// Creates an ApiKeyV3 from an APIKey V1/V2 format (GUID).
        /// </summary>
        public static ApiKeyV3 CreateFromV1V2ApiKey(string plaintextApiKey)
        {
            // Since V1/V2/V3 have the same format (Guid), we can use the same parse method
            if (!TryParse(plaintextApiKey, out ApiKeyV3 apiKeyV3))
            {
                throw new ArgumentException("Invalid format for ApiKey V1/V2");
            }

            apiKeyV3.HashedApiKey = apiKeyV3.IdPart + V3Hasher.GenerateHash(apiKeyV3.PasswordPart);

            return(apiKeyV3);
        }
예제 #3
0
        /// <summary>
        /// Verified this ApiKey with provided hashed ApiKey.
        /// </summary>
        public bool Verify(string hashedApiKey)
        {
            if (string.IsNullOrWhiteSpace(hashedApiKey) || hashedApiKey.Length != IdAndPasswordHashedLength)
            {
                return(false);
            }

            string hashedApiKeyIdPart       = hashedApiKey.Substring(0, IdPartLength);
            string hashedApiKeyPasswordPart = hashedApiKey.Substring(IdPartLength);

            if (!string.Equals(IdPart, Normalize(hashedApiKeyIdPart)))
            {
                return(false);
            }

            return(V3Hasher.VerifyHash(hashedApiKeyPasswordPart, PasswordPart));
        }
예제 #4
0
        /// <summary>
        /// Verified this ApiKey with provided hashed ApiKey.
        /// </summary>
        public bool Verify(string hashedApiKey)
        {
            if (string.IsNullOrWhiteSpace(hashedApiKey) || hashedApiKey.Length != IdAndPasswordHashedLength)
            {
                return(false);
            }

            string hashedApiKeyIdPart       = hashedApiKey.Substring(0, IdPartBase32Length);
            string hashedApiKeyPasswordPart = hashedApiKey.Substring(IdPartBase32Length);

            if (!string.Equals(IdPart, Normalize(hashedApiKeyIdPart)))
            {
                return(false);
            }

            // The verification is not case sensitive. This is to maintain the existing behavior that ApiKey authentication is not case-sensitive.
            return(V3Hasher.VerifyHash(hashedApiKeyPasswordPart.ToUpper().FromBase32String(), PasswordPart));
        }
예제 #5
0
 public Credential CreatePasswordCredential(string plaintextPassword)
 {
     return(new Credential(
                LatestPasswordType,
                V3Hasher.GenerateHash(plaintextPassword)));
 }