summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.c18
-rw-r--r--src/cookie.c65
-rw-r--r--src/cookie.h3
-rw-r--r--src/crypto/chacha20poly1305.c110
-rw-r--r--src/crypto/chacha20poly1305.h11
-rw-r--r--src/messages.h4
-rw-r--r--src/peer.c1
-rw-r--r--src/selftest/chacha20poly1305.h35
8 files changed, 204 insertions, 43 deletions
diff --git a/src/config.c b/src/config.c
index 741cace..c061b2d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -116,6 +116,7 @@ int config_set_device(struct wireguard_device *wg, void __user *user_device)
size_t i, offset;
struct wgdevice in_device;
void __user *user_peer;
+ bool modified_static_identity = false;
BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN);
BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN);
@@ -136,15 +137,24 @@ int config_set_device(struct wireguard_device *wg, void __user *user_device)
if (in_device.replace_peer_list)
peer_remove_all(wg);
- if (in_device.remove_private_key)
+ if (in_device.remove_private_key) {
noise_set_static_identity_private_key(&wg->static_identity, NULL);
- else if (memcmp(zeros, in_device.private_key, WG_KEY_LEN))
+ modified_static_identity = true;
+ } else if (memcmp(zeros, in_device.private_key, WG_KEY_LEN)) {
noise_set_static_identity_private_key(&wg->static_identity, in_device.private_key);
+ modified_static_identity = true;
+ }
- if (in_device.remove_preshared_key)
+ if (in_device.remove_preshared_key) {
noise_set_static_identity_preshared_key(&wg->static_identity, NULL);
- else if (memcmp(zeros, in_device.preshared_key, WG_KEY_LEN))
+ modified_static_identity = true;
+ } else if (memcmp(zeros, in_device.preshared_key, WG_KEY_LEN)) {
noise_set_static_identity_preshared_key(&wg->static_identity, in_device.preshared_key);
+ modified_static_identity = true;
+ }
+
+ if (modified_static_identity)
+ cookie_checker_precompute_keys(&wg->cookie_checker, NULL);
for (i = 0, offset = 0, user_peer = user_device + sizeof(struct wgdevice); i < in_device.num_peers; ++i, user_peer += offset) {
ret = set_peer(wg, user_peer, &offset);
diff --git a/src/cookie.c b/src/cookie.c
index a2d1b22..b0f1284 100644
--- a/src/cookie.c
+++ b/src/cookie.c
@@ -23,6 +23,31 @@ int cookie_checker_init(struct cookie_checker *checker, struct wireguard_device
return 0;
}
+static int precompute_peer_key(struct wireguard_peer *peer, void *psk)
+{
+ blake2s(peer->latest_cookie.cookie_decryption_key, peer->handshake.remote_static, psk, NOISE_SYMMETRIC_KEY_LEN, NOISE_PUBLIC_KEY_LEN, psk ? NOISE_SYMMETRIC_KEY_LEN : 0);
+ return 0;
+}
+
+void cookie_checker_precompute_keys(struct cookie_checker *checker, struct wireguard_peer *peer)
+{
+ down_read(&checker->device->static_identity.lock);
+ if (unlikely(checker->device->static_identity.has_identity)) {
+ memset(checker->cookie_encryption_key, 0, NOISE_SYMMETRIC_KEY_LEN);
+ goto out;
+ }
+
+ if (peer)
+ precompute_peer_key(peer, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL);
+ else {
+ blake2s(checker->cookie_encryption_key, checker->device->static_identity.static_public, checker->device->static_identity.preshared_key, NOISE_SYMMETRIC_KEY_LEN, NOISE_PUBLIC_KEY_LEN, checker->device->static_identity.has_psk ? NOISE_SYMMETRIC_KEY_LEN : 0);
+ peer_for_each_unlocked(checker->device, precompute_peer_key, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL);
+ }
+
+out:
+ up_read(&checker->device->static_identity.lock);
+}
+
void cookie_checker_uninit(struct cookie_checker *checker)
{
ratelimiter_uninit(&checker->ratelimiter);
@@ -159,32 +184,16 @@ void cookie_add_mac_to_packet(void *message, size_t len, struct wireguard_peer *
void cookie_message_create(struct message_handshake_cookie *dst, struct sk_buff *skb, void *data_start, size_t data_len, __le32 index, struct cookie_checker *checker)
{
struct message_macs *macs = (struct message_macs *)((u8 *)data_start + data_len - sizeof(struct message_macs));
- struct blake2s_state state;
u8 key[NOISE_SYMMETRIC_KEY_LEN];
u8 cookie[COOKIE_LEN];
dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE);
dst->receiver_index = index;
- get_random_bytes(dst->salt, COOKIE_SALT_LEN);
- blake2s(dst->salt, dst->salt, NULL, COOKIE_SALT_LEN, COOKIE_SALT_LEN, 0); /* Avoid directly transmitting RNG output. */
-
- down_read(&checker->device->static_identity.lock);
- if (unlikely(!checker->device->static_identity.has_identity)) {
- memset(dst, 0, sizeof(struct message_handshake_cookie));
- up_read(&checker->device->static_identity.lock);
- return;
- }
- if (checker->device->static_identity.has_psk)
- blake2s_init_key(&state, NOISE_SYMMETRIC_KEY_LEN, checker->device->static_identity.preshared_key, NOISE_SYMMETRIC_KEY_LEN);
- else
- blake2s_init(&state, NOISE_SYMMETRIC_KEY_LEN);
- blake2s_update(&state, checker->device->static_identity.static_public, NOISE_PUBLIC_KEY_LEN);
- up_read(&checker->device->static_identity.lock);
- blake2s_update(&state, dst->salt, COOKIE_SALT_LEN);
- blake2s_final(&state, key, NOISE_SYMMETRIC_KEY_LEN);
+ get_random_bytes(dst->nonce, COOKIE_NONCE_LEN);
+ blake2s(dst->nonce, dst->nonce, NULL, COOKIE_NONCE_LEN, COOKIE_NONCE_LEN, 0); /* Avoid directly transmitting RNG output. */
make_cookie(cookie, skb, checker);
- chacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN, macs->mac1, COOKIE_LEN, 0, key);
+ xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN, macs->mac1, COOKIE_LEN, dst->nonce, checker->cookie_encryption_key);
memzero_explicit(key, NOISE_HASH_LEN);
memzero_explicit(cookie, COOKIE_LEN);
@@ -192,7 +201,6 @@ void cookie_message_create(struct message_handshake_cookie *dst, struct sk_buff
void cookie_message_consume(struct message_handshake_cookie *src, struct wireguard_device *wg)
{
- struct blake2s_state state;
u8 key[NOISE_SYMMETRIC_KEY_LEN];
u8 cookie[COOKIE_LEN];
struct index_hashtable_entry *entry;
@@ -208,23 +216,8 @@ void cookie_message_consume(struct message_handshake_cookie *src, struct wiregua
}
up_read(&entry->peer->latest_cookie.lock);
- down_read(&wg->static_identity.lock);
- if (unlikely(!wg->static_identity.has_identity)) {
- up_read(&wg->static_identity.lock);
- goto out;
- }
- if (wg->static_identity.has_psk)
- blake2s_init_key(&state, NOISE_SYMMETRIC_KEY_LEN, wg->static_identity.preshared_key, NOISE_SYMMETRIC_KEY_LEN);
- else
- blake2s_init(&state, NOISE_SYMMETRIC_KEY_LEN);
- up_read(&wg->static_identity.lock);
-
- blake2s_update(&state, entry->peer->handshake.remote_static, NOISE_PUBLIC_KEY_LEN);
- blake2s_update(&state, src->salt, COOKIE_SALT_LEN);
- blake2s_final(&state, key, NOISE_SYMMETRIC_KEY_LEN);
-
down_write(&entry->peer->latest_cookie.lock);
- if (chacha20poly1305_decrypt(cookie, src->encrypted_cookie, sizeof(src->encrypted_cookie), entry->peer->latest_cookie.last_mac1_sent, COOKIE_LEN, 0, key)) {
+ if (xchacha20poly1305_decrypt(cookie, src->encrypted_cookie, sizeof(src->encrypted_cookie), entry->peer->latest_cookie.last_mac1_sent, COOKIE_LEN, src->nonce, entry->peer->latest_cookie.cookie_decryption_key)) {
memcpy(entry->peer->latest_cookie.cookie, cookie, COOKIE_LEN);
entry->peer->latest_cookie.birthdate = get_jiffies_64();
entry->peer->latest_cookie.is_valid = true;
diff --git a/src/cookie.h b/src/cookie.h
index 4ea20e1..13c646d 100644
--- a/src/cookie.h
+++ b/src/cookie.h
@@ -13,6 +13,7 @@ struct sk_buff;
struct cookie_checker {
u8 secret[NOISE_HASH_LEN];
+ u8 cookie_encryption_key[NOISE_SYMMETRIC_KEY_LEN];
u64 secret_birthdate;
struct rw_semaphore secret_lock;
struct ratelimiter ratelimiter;
@@ -25,6 +26,7 @@ struct cookie {
u8 cookie[COOKIE_LEN];
bool have_sent_mac1;
u8 last_mac1_sent[COOKIE_LEN];
+ u8 cookie_decryption_key[NOISE_SYMMETRIC_KEY_LEN];
struct rw_semaphore lock;
};
@@ -37,6 +39,7 @@ enum cookie_mac_state {
int cookie_checker_init(struct cookie_checker *checker, struct wireguard_device *wg);
void cookie_checker_uninit(struct cookie_checker *checker);
+void cookie_checker_precompute_keys(struct cookie_checker *checker, struct wireguard_peer *peer);
void cookie_init(struct cookie *cookie);
enum cookie_mac_state cookie_validate_packet(struct cookie_checker *checker, struct sk_buff *skb, void *data_start, size_t data_len, bool check_cookie);
diff --git a/src/crypto/chacha20poly1305.c b/src/crypto/chacha20poly1305.c
index a7421d6..3b860bf 100644
--- a/src/crypto/chacha20poly1305.c
+++ b/src/crypto/chacha20poly1305.c
@@ -52,6 +52,11 @@ static inline u32 le32_to_cpuvp(const void *p)
return le32_to_cpup(p);
}
+static inline u64 le64_to_cpuvp(const void *p)
+{
+ return le64_to_cpup(p);
+}
+
static inline u32 rotl32(u32 v, u8 n)
{
return (v << n) | (v >> (sizeof(v) * 8 - n));
@@ -133,9 +138,85 @@ static void chacha20_generic_block(struct chacha20_ctx *ctx, void *stream)
ctx->state[12]++;
}
+static const char constant[16] = "expand 32-byte k";
+
+static void hchacha20(u8 derived_key[CHACHA20POLY1305_KEYLEN], const u8 nonce[16], const u8 key[CHACHA20POLY1305_KEYLEN])
+{
+ u32 x[CHACHA20_BLOCK_SIZE / sizeof(u32)];
+ __le32 *out = (__force __le32 *)derived_key;
+ int i;
+
+ x[0] = le32_to_cpuvp(constant + 0);
+ x[1] = le32_to_cpuvp(constant + 4);
+ x[2] = le32_to_cpuvp(constant + 8);
+ x[3] = le32_to_cpuvp(constant + 12);
+ x[4] = le32_to_cpuvp(key + 0);
+ x[5] = le32_to_cpuvp(key + 4);
+ x[6] = le32_to_cpuvp(key + 8);
+ x[7] = le32_to_cpuvp(key + 12);
+ x[8] = le32_to_cpuvp(key + 16);
+ x[9] = le32_to_cpuvp(key + 20);
+ x[10] = le32_to_cpuvp(key + 24);
+ x[11] = le32_to_cpuvp(key + 28);
+ x[12] = le32_to_cpuvp(nonce + 0);
+ x[13] = le32_to_cpuvp(nonce + 4);
+ x[14] = le32_to_cpuvp(nonce + 8);
+ x[15] = le32_to_cpuvp(nonce + 12);
+
+ for (i = 0; i < 20; i += 2) {
+ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16);
+ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16);
+ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16);
+ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16);
+
+ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12);
+ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12);
+ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12);
+ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12);
+
+ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8);
+ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8);
+ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8);
+ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8);
+
+ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7);
+ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7);
+ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7);
+ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7);
+
+ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16);
+ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16);
+ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16);
+ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16);
+
+ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12);
+ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12);
+ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12);
+ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12);
+
+ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8);
+ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8);
+ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8);
+ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8);
+
+ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7);
+ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7);
+ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7);
+ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7);
+ }
+
+ out[0] = cpu_to_le32(x[0]);
+ out[1] = cpu_to_le32(x[1]);
+ out[2] = cpu_to_le32(x[2]);
+ out[3] = cpu_to_le32(x[3]);
+ out[4] = cpu_to_le32(x[12]);
+ out[5] = cpu_to_le32(x[13]);
+ out[6] = cpu_to_le32(x[14]);
+ out[7] = cpu_to_le32(x[15]);
+}
+
static void chacha20_keysetup(struct chacha20_ctx *ctx, const u8 key[CHACHA20_KEY_SIZE], const u8 nonce[sizeof(u64)])
{
- static const char constant[16] = "expand 32-byte k";
ctx->state[0] = le32_to_cpuvp(constant + 0);
ctx->state[1] = le32_to_cpuvp(constant + 4);
ctx->state[2] = le32_to_cpuvp(constant + 8);
@@ -700,4 +781,31 @@ bool chacha20poly1305_decrypt_sg(struct scatterlist *dst, struct scatterlist *sr
return !ret;
}
+
+bool xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
+ const u8 *ad, const size_t ad_len,
+ const u8 nonce[XCHACHA20POLY1305_NONCELEN],
+ const u8 key[CHACHA20POLY1305_KEYLEN])
+{
+ u8 derived_key[CHACHA20POLY1305_KEYLEN];
+ bool ret;
+ hchacha20(derived_key, nonce, key);
+ ret = chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, le64_to_cpuvp(nonce + 16), derived_key);
+ memzero_explicit(derived_key, CHACHA20POLY1305_KEYLEN);
+ return ret;
+}
+
+bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
+ const u8 *ad, const size_t ad_len,
+ const u8 nonce[XCHACHA20POLY1305_NONCELEN],
+ const u8 key[CHACHA20POLY1305_KEYLEN])
+{
+ u8 derived_key[CHACHA20POLY1305_KEYLEN];
+ bool ret;
+ hchacha20(derived_key, nonce, key);
+ ret = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, le64_to_cpuvp(nonce + 16), derived_key);
+ memzero_explicit(derived_key, CHACHA20POLY1305_KEYLEN);
+ return ret;
+}
+
#include "../selftest/chacha20poly1305.h"
diff --git a/src/crypto/chacha20poly1305.h b/src/crypto/chacha20poly1305.h
index 2ae9ff5..068995a 100644
--- a/src/crypto/chacha20poly1305.h
+++ b/src/crypto/chacha20poly1305.h
@@ -8,6 +8,7 @@
struct scatterlist;
enum chacha20poly1305_lengths {
+ XCHACHA20POLY1305_NONCELEN = 24,
CHACHA20POLY1305_KEYLEN = 32,
CHACHA20POLY1305_AUTHTAGLEN = 16
};
@@ -31,6 +32,16 @@ bool chacha20poly1305_decrypt_sg(struct scatterlist *dst, struct scatterlist *sr
const u8 *ad, const size_t ad_len,
const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]);
+bool xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
+ const u8 *ad, const size_t ad_len,
+ const u8 nonce[XCHACHA20POLY1305_NONCELEN],
+ const u8 key[CHACHA20POLY1305_KEYLEN]);
+
+bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
+ const u8 *ad, const size_t ad_len,
+ const u8 nonce[XCHACHA20POLY1305_NONCELEN],
+ const u8 key[CHACHA20POLY1305_KEYLEN]);
+
#ifdef CONFIG_X86_64
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
diff --git a/src/messages.h b/src/messages.h
index f5362ac..8fa1c95 100644
--- a/src/messages.h
+++ b/src/messages.h
@@ -27,7 +27,7 @@ enum noise_lengths {
enum cookie_values {
COOKIE_SECRET_MAX_AGE = 2 * 60 * HZ,
COOKIE_SECRET_LATENCY = 5 * HZ,
- COOKIE_SALT_LEN = 32,
+ COOKIE_NONCE_LEN = XCHACHA20POLY1305_NONCELEN,
COOKIE_LEN = 16
};
@@ -99,7 +99,7 @@ struct message_handshake_response {
struct message_handshake_cookie {
struct message_header header;
__le32 receiver_index;
- u8 salt[COOKIE_SALT_LEN];
+ u8 nonce[COOKIE_NONCE_LEN];
u8 encrypted_cookie[noise_encrypted_len(COOKIE_LEN)];
};
diff --git a/src/peer.c b/src/peer.c
index 38a7ae1..ae54fb7 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -35,6 +35,7 @@ struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_
peer->device = wg;
cookie_init(&peer->latest_cookie);
noise_handshake_init(&peer->handshake, &wg->static_identity, public_key, peer);
+ cookie_checker_precompute_keys(&wg->cookie_checker, peer);
mutex_init(&peer->keypairs.keypair_update_lock);
INIT_WORK(&peer->transmit_handshake_work, packet_send_queued_handshakes);
rwlock_init(&peer->endpoint_lock);
diff --git a/src/selftest/chacha20poly1305.h b/src/selftest/chacha20poly1305.h
index 455d58b..1d79299 100644
--- a/src/selftest/chacha20poly1305.h
+++ b/src/selftest/chacha20poly1305.h
@@ -25,6 +25,25 @@ static const struct chacha20poly1305_testvec chacha20poly1305_dec_vectors[] = {
.result = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d"
} };
+static const struct chacha20poly1305_testvec xchacha20poly1305_enc_vectors[] = { {
+ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0",
+ .nonce = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17",
+ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91",
+ .alen = 12,
+ .input = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d",
+ .ilen = 265,
+ .result = "\x1a\x6e\x3a\xd9\xfd\x41\x3f\x77\x54\x72\x0a\x70\x9a\xa0\x29\x92\x2e\xed\x93\xcf\x0f\x71\x88\x18\x7a\x9d\x2d\x24\xe0\xf5\xea\x3d\x55\x64\xd7\xad\x2a\x1a\x1f\x7e\x86\x6d\xb0\xce\x80\x41\x72\x86\x26\xee\x84\xd7\xef\x82\x9e\xe2\x60\x9d\x5a\xfc\xf0\xe4\x19\x85\xea\x09\xc6\xfb\xb3\xa9\x50\x09\xec\x5e\x11\x90\xa1\xc5\x4e\x49\xef\x50\xd8\x8f\xe0\x78\xd7\xfd\xb9\x3b\xc9\xf2\x91\xc8\x25\xc8\xa7\x63\x60\xce\x10\xcd\xc6\x7f\xf8\x16\xf8\xe1\x0a\xd9\xde\x79\x50\x33\xf2\x16\x0f\x17\xba\xb8\x5d\xd8\xdf\x4e\x51\xa8\x39\xd0\x85\xca\x46\x6a\x10\xa7\xa3\x88\xef\x79\xb9\xf8\x24\xf3\xe0\x71\x7b\x76\x28\x46\x3a\x3a\x1b\x91\xb6\xd4\x3e\x23\xe5\x44\x15\xbf\x60\x43\x9d\xa4\xbb\xd5\x5f\x89\xeb\xef\x8e\xfd\xdd\xb4\x0d\x46\xf0\x69\x23\x63\xae\x94\xf5\x5e\xa5\xad\x13\x1c\x41\x76\xe6\x90\xd6\x6d\xa2\x8f\x97\x4c\xa8\x0b\xcf\x8d\x43\x2b\x9c\x9b\xc5\x58\xa5\xb6\x95\x9a\xbf\x81\xc6\x54\xc9\x66\x0c\xe5\x4f\x6a\x53\xa1\xe5\x0c\xba\x31\xde\x34\x64\x73\x8a\x3b\xbd\x92\x01\xdb\x71\x69\xf3\x58\x99\xbc\xd1\xcb\x4a\x05\xe2\x58\x9c\x25\x17\xcd\xdc\x83\xb7\xff\xfb\x09\x61\xad\xbf\x13\x5b\x5e\xed\x46\x82\x6f\x22\xd8\x93\xa6\x85\x5b\x40\x39\x5c\xc5\x9c"
+} };
+static const struct chacha20poly1305_testvec xchacha20poly1305_dec_vectors[] = { {
+ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0",
+ .nonce = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17",
+ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91",
+ .alen = 12,
+ .input = "\x1a\x6e\x3a\xd9\xfd\x41\x3f\x77\x54\x72\x0a\x70\x9a\xa0\x29\x92\x2e\xed\x93\xcf\x0f\x71\x88\x18\x7a\x9d\x2d\x24\xe0\xf5\xea\x3d\x55\x64\xd7\xad\x2a\x1a\x1f\x7e\x86\x6d\xb0\xce\x80\x41\x72\x86\x26\xee\x84\xd7\xef\x82\x9e\xe2\x60\x9d\x5a\xfc\xf0\xe4\x19\x85\xea\x09\xc6\xfb\xb3\xa9\x50\x09\xec\x5e\x11\x90\xa1\xc5\x4e\x49\xef\x50\xd8\x8f\xe0\x78\xd7\xfd\xb9\x3b\xc9\xf2\x91\xc8\x25\xc8\xa7\x63\x60\xce\x10\xcd\xc6\x7f\xf8\x16\xf8\xe1\x0a\xd9\xde\x79\x50\x33\xf2\x16\x0f\x17\xba\xb8\x5d\xd8\xdf\x4e\x51\xa8\x39\xd0\x85\xca\x46\x6a\x10\xa7\xa3\x88\xef\x79\xb9\xf8\x24\xf3\xe0\x71\x7b\x76\x28\x46\x3a\x3a\x1b\x91\xb6\xd4\x3e\x23\xe5\x44\x15\xbf\x60\x43\x9d\xa4\xbb\xd5\x5f\x89\xeb\xef\x8e\xfd\xdd\xb4\x0d\x46\xf0\x69\x23\x63\xae\x94\xf5\x5e\xa5\xad\x13\x1c\x41\x76\xe6\x90\xd6\x6d\xa2\x8f\x97\x4c\xa8\x0b\xcf\x8d\x43\x2b\x9c\x9b\xc5\x58\xa5\xb6\x95\x9a\xbf\x81\xc6\x54\xc9\x66\x0c\xe5\x4f\x6a\x53\xa1\xe5\x0c\xba\x31\xde\x34\x64\x73\x8a\x3b\xbd\x92\x01\xdb\x71\x69\xf3\x58\x99\xbc\xd1\xcb\x4a\x05\xe2\x58\x9c\x25\x17\xcd\xdc\x83\xb7\xff\xfb\x09\x61\xad\xbf\x13\x5b\x5e\xed\x46\x82\x6f\x22\xd8\x93\xa6\x85\x5b\x40\x39\x5c\xc5\x9c",
+ .ilen = 281,
+ .result = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d"
+} };
+
bool chacha20poly1305_selftest(void)
{
size_t i;
@@ -47,6 +66,22 @@ bool chacha20poly1305_selftest(void)
success = false;
}
}
+ for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_enc_vectors); ++i) {
+ memset(computed_result, 0, sizeof(computed_result));
+ success = xchacha20poly1305_encrypt(computed_result, xchacha20poly1305_enc_vectors[i].input, xchacha20poly1305_enc_vectors[i].ilen, xchacha20poly1305_enc_vectors[i].assoc, xchacha20poly1305_enc_vectors[i].alen, xchacha20poly1305_enc_vectors[i].nonce, xchacha20poly1305_enc_vectors[i].key);
+ if (memcmp(computed_result, xchacha20poly1305_enc_vectors[i].result, xchacha20poly1305_enc_vectors[i].ilen + POLY1305_MAC_SIZE)) {
+ pr_info("xchacha20poly1305 encryption self-test %zu: FAIL\n", i + 1);
+ success = false;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_dec_vectors); ++i) {
+ memset(computed_result, 0, sizeof(computed_result));
+ success = xchacha20poly1305_decrypt(computed_result, xchacha20poly1305_dec_vectors[i].input, xchacha20poly1305_dec_vectors[i].ilen, xchacha20poly1305_dec_vectors[i].assoc, xchacha20poly1305_dec_vectors[i].alen, xchacha20poly1305_dec_vectors[i].nonce, xchacha20poly1305_dec_vectors[i].key);
+ if (!success || memcmp(computed_result, xchacha20poly1305_dec_vectors[i].result, xchacha20poly1305_dec_vectors[i].ilen - POLY1305_MAC_SIZE)) {
+ pr_info("xchacha20poly1305 decryption self-test %zu: FAIL\n", i + 1);
+ success = false;
+ }
+ }
if (success)
pr_info("chacha20poly1305 self-tests: pass\n");
return success;