3 * Copyright (c) 2019 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * Hashed message authentication code functions using OpenSSL.
21 #include <arpa/inet.h>
30 #define SRP_CRYPTO_OPENSSL_INTERNAL
31 #include "srp-crypto.h"
33 // Function to generate a signature given some data and a private key
35 srp_hmac_iov(hmac_key_t
*key
, uint8_t *output
, size_t max
, struct iovec
*iov
, int count
)
39 uint8_t kipad
[SRP_SHA256_BLOCK_SIZE
], kopad
[SRP_SHA256_BLOCK_SIZE
], intermediate
[SRP_SHA256_HASH_SIZE
];
40 EVP_MD_CTX inner
, outer
;
44 if (key
->algorithm
!= SRP_HMAC_TYPE_SHA256
) {
45 ERROR("srp_hmac_iov: unsupported HMAC hash algorithm: %d", key
->algorithm
);
48 if (max
< SRP_SHA256_HASH_SIZE
) {
49 ERROR("srp_hmac_iov: not enough space in output buffer (%lu) for hash (%d).",
50 (unsigned long)max
, SRP_SHA256_HASH_SIZE
);
55 EVP_MD_CTX_INIT(&inner
);
57 // If the key is longer than the block size, hash it and use the digest as the key.
58 if (key
->length
> SRP_SHA256_BLOCK_SIZE
) {
59 if ((status
= EVP_DigestInit(&inner
, md
)) != 0) {
60 ERROR("srp_hmac_iov failed to initialize key digest");
64 if ((status
= EVP_DigestUpdate(&inner
, key
, key
->length
)) != 0) {
65 ERROR("srp_hmac_iov failed to hash key");
68 if ((status
= EVP_DigestFinal(&inner
, intermediate
, SRP_SHA256_HASH_SIZE
)) != 0) {
69 ERROR("srp_hmac_iov failed to digest key");
72 EVP_MD_CTX_INIT(&inner
);
75 // Compute key ^ kipad and key ^ kopad
76 for (i
= 0; i
< SRP_SHA256_BLOCK_SIZE
; i
++) {
77 uint8_t byte
= i
>= key
->length
? 0 : key
->secret
[i
];
78 kipad
[i
] = byte
^ 0x36;
79 kopad
[i
] = byte
^ 0x5c;
82 if ((status
= EVP_DigestInit(&inner
, md
)) != 0) {
83 ERROR("srp_hmac_iov failed to initialize inner digest");
86 // Compute H(K xor ipad, text)
87 if ((status
= EVP_DigestUpdate(&inner
, kipad
, SRP_SHA256_BLOCK_SIZE
)) != 0) {
88 ERROR("srp_hmac_iov failed to hash ipad to inner digest");
91 for (i
= 0; i
< count
; i
++) {
92 if ((status
= EVP_DigestUpdate(&inner
, iov
[i
].iov_base
, iov
[i
].iov_len
)) != 0) {
93 ERROR("srp_hmac_iov failed to hash chunk %d to inner digest", i
);
97 if ((status
= EVP_DigestFinal(&inner
, intermediate
, SRP_SHA256_HASH_SIZE
)) != 0) {
98 ERROR("srp_hmac_iov failed to hash ipad to inner digest");
102 // Compute H(K xor opad, H(K xor ipad, text))
103 EVP_MD_CTX_INIT(&outer
);
104 if ((status
= EVP_DigestInit(&outer
, md
)) != 0) {
105 ERROR("srp_hmac_iov failed to initialize outer digest");
108 if ((status
= EVP_DigestUpdate(&outer
, kopad
, SRP_SHA256_BLOCK_SIZE
)) != 0) {
109 ERROR("srp_hmac_iov failed to hash outer pad");
113 if ((status
= EVP_DigestUpdate(&outer
, intermediate
, SRP_SHA256_HASH_SIZE
)) != 0) {
114 ERROR("srp_hmac_iov failed to hash outer digest");
118 if ((status
= EVP_DigestFinal(&outer
, output
, max
)) != 0) {
119 ERROR("srp_hmac_iov failed to hash outer outer pad with inner digest");
122 // Bob's your uncle...
126 srp_base64_parse(char *src
, size_t *len_ret
, uint8_t *buf
, size_t buflen
)
128 size_t slen
= strlen(src
);
129 int ret
= mbedtls_base64_decode(buf
, buflen
, len_ret
, (const unsigned char *)src
, slen
);
130 if (ret
== MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL
) {
132 } else if (ret
== MBEDTLS_ERR_BASE64_INVALID_CHARACTER
) {
134 } else if (ret
< 0) {
143 // c-file-style: "bsd"
146 // indent-tabs-mode: nil