-
Notifications
You must be signed in to change notification settings - Fork 18
/
glome.c
136 lines (116 loc) · 4.74 KB
/
glome.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "glome.h"
#include <assert.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
#include <openssl/sha.h>
#include <string.h>
#define X25519_SHARED_KEY_LEN 32
int glome_generate_key(uint8_t private_key[GLOME_MAX_PRIVATE_KEY_LENGTH],
uint8_t public_key[GLOME_MAX_PUBLIC_KEY_LENGTH]) {
size_t public_key_len = GLOME_MAX_PUBLIC_KEY_LENGTH;
size_t private_key_len = GLOME_MAX_PRIVATE_KEY_LENGTH;
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
int err =
(ctx == NULL || EVP_PKEY_keygen_init(ctx) != 1 ||
EVP_PKEY_keygen(ctx, &pkey) != 1 ||
EVP_PKEY_get_raw_public_key(pkey, public_key, &public_key_len) != 1 ||
public_key_len != GLOME_MAX_PUBLIC_KEY_LENGTH ||
EVP_PKEY_get_raw_private_key(pkey, private_key, &private_key_len) != 1 ||
private_key_len != GLOME_MAX_PRIVATE_KEY_LENGTH);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return err;
}
int glome_derive_key(const uint8_t private_key[GLOME_MAX_PRIVATE_KEY_LENGTH],
uint8_t public_key[GLOME_MAX_PUBLIC_KEY_LENGTH]) {
size_t public_key_length = GLOME_MAX_PUBLIC_KEY_LENGTH;
EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key(
EVP_PKEY_X25519, NULL, private_key, GLOME_MAX_PRIVATE_KEY_LENGTH);
int err =
(pkey == NULL ||
EVP_PKEY_get_raw_public_key(pkey, public_key, &public_key_length) != 1 ||
public_key_length != GLOME_MAX_PUBLIC_KEY_LENGTH);
EVP_PKEY_free(pkey);
return err;
}
int glome_tag(bool verify, unsigned char counter,
const uint8_t private_key[GLOME_MAX_PRIVATE_KEY_LENGTH],
const uint8_t peer_key[GLOME_MAX_PUBLIC_KEY_LENGTH],
const uint8_t *message, size_t message_len,
uint8_t tag[GLOME_MAX_TAG_LENGTH]) {
uint8_t hmac_key[X25519_SHARED_KEY_LEN + 2 * GLOME_MAX_PUBLIC_KEY_LENGTH] = {
0};
uint8_t public_key[GLOME_MAX_PUBLIC_KEY_LENGTH] = {0};
EVP_PKEY *evp_peer_key = EVP_PKEY_new_raw_public_key(
EVP_PKEY_X25519, NULL, peer_key, GLOME_MAX_PUBLIC_KEY_LENGTH);
EVP_PKEY *evp_private_key = EVP_PKEY_new_raw_private_key(
EVP_PKEY_X25519, NULL, private_key, GLOME_MAX_PRIVATE_KEY_LENGTH);
if (evp_private_key == NULL || evp_peer_key == NULL) {
EVP_PKEY_free(evp_peer_key);
EVP_PKEY_free(evp_private_key);
return 1;
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evp_private_key, NULL);
if (ctx == NULL) {
EVP_PKEY_free(evp_peer_key);
EVP_PKEY_free(evp_private_key);
return 1;
}
// Derive public key.
size_t public_key_length = GLOME_MAX_PUBLIC_KEY_LENGTH;
int err = (EVP_PKEY_get_raw_public_key(evp_private_key, public_key,
&public_key_length) != 1 ||
public_key_length != GLOME_MAX_PUBLIC_KEY_LENGTH);
if (err) {
EVP_PKEY_free(evp_peer_key);
EVP_PKEY_free(evp_private_key);
return 1;
}
// X25519 shared secret
size_t shared_key_length = X25519_SHARED_KEY_LEN;
err = (EVP_PKEY_derive_init(ctx) != 1 ||
EVP_PKEY_derive_set_peer(ctx, evp_peer_key) != 1 ||
EVP_PKEY_derive(ctx, hmac_key, &shared_key_length) != 1 ||
shared_key_length != X25519_SHARED_KEY_LEN);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(evp_peer_key);
EVP_PKEY_free(evp_private_key);
if (err) {
return 1;
}
// hmac_key := (sharded_key | verifier_key | signer_key)
memcpy(hmac_key + X25519_SHARED_KEY_LEN, (verify ? public_key : peer_key),
GLOME_MAX_PUBLIC_KEY_LENGTH);
memcpy(hmac_key + X25519_SHARED_KEY_LEN + GLOME_MAX_PUBLIC_KEY_LENGTH,
(verify ? peer_key : public_key), GLOME_MAX_PUBLIC_KEY_LENGTH);
// data := (counter | message)
size_t data_len = message_len + sizeof counter;
uint8_t *data = malloc(data_len);
if (data == NULL) {
return 1;
}
memcpy(data, &counter, sizeof counter);
memcpy(data + sizeof counter, message, message_len);
unsigned int tag_length = GLOME_MAX_TAG_LENGTH;
int success = (HMAC(EVP_sha256(), hmac_key, sizeof hmac_key, data, data_len,
tag, &tag_length) &&
tag_length == GLOME_MAX_TAG_LENGTH);
free(data);
return success ? 0 : 1;
}