2 * fast-crypto.c Cryptographic functions for EAP-FAST.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2016 Alan DeKok <aland@freeradius.org>
21 * Copyright 2016 The FreeRADIUS server project
25 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
28 #include <freeradius-devel/libradius.h>
30 #include <openssl/evp.h>
31 #include <openssl/aes.h>
32 #include <openssl/err.h>
34 #include "eap_fast_crypto.h"
36 // http://stackoverflow.com/a/29838852
37 static void NEVER_RETURNS handleErrors(void)
39 unsigned long errCode;
41 fprintf(stderr, "An error occurred\n");
42 while((errCode = ERR_get_error()))
44 char *err = ERR_error_string(errCode, NULL);
45 fprintf(stderr, "%s\n", err);
50 // https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode
51 int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len,
52 uint8_t const *aad, size_t aad_len,
53 uint8_t const *key, uint8_t *iv, unsigned char *ciphertext,
63 /* Create and initialise the context */
64 if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
66 /* Initialise the encryption operation. */
67 if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
70 /* Set IV length if default 12 bytes (96 bits) is not appropriate */
71 if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
74 /* Initialise key and IV */
75 if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
77 /* Provide any AAD data. This can be called zero or more times as
80 if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
83 /* Provide the message to be encrypted, and obtain the encrypted output.
84 * EVP_EncryptUpdate can be called multiple times if necessary
86 if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
90 /* Finalise the encryption. Normally ciphertext bytes may be written at
91 * this stage, but this does not occur in GCM mode
93 if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
94 ciphertext_len += len;
97 if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
101 EVP_CIPHER_CTX_free(ctx);
103 return ciphertext_len;
106 int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len,
107 uint8_t const *aad, size_t aad_len,
108 uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext)
115 /* Create and initialise the context */
116 if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
118 /* Initialise the decryption operation. */
119 if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
122 /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
123 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
126 /* Initialise key and IV */
127 if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
129 /* Provide any AAD data. This can be called zero or more times as
132 if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
135 /* Provide the message to be decrypted, and obtain the plaintext output.
136 * EVP_DecryptUpdate can be called multiple times if necessary
138 if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
145 memcpy(&tmp, &tag, sizeof(tmp));
147 /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
148 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tmp)) handleErrors();
151 /* Finalise the decryption. A positive return value indicates success,
152 * anything else is a failure - the plaintext is not trustworthy.
154 ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
157 EVP_CIPHER_CTX_free(ctx);
162 plaintext_len += len;
163 return plaintext_len;