mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-11-16 12:30:28 +00:00
We were pointing to the old mobylinux docker hub repo. Let's update the kernel build to be the new style one. Note that I didn't bump the kernel version or update the patches at all. We should do this soon, but for the purposes of our probational channel PoC, I'm leaving wireguard at the old version for now. Signed-off-by: Tycho Andersen <tycho@docker.com>
11840 lines
449 KiB
Diff
11840 lines
449 KiB
Diff
--- /dev/null
|
|
+++ b/net/wireguard/config.c
|
|
@@ -0,0 +1,321 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "config.h"
|
|
+#include "device.h"
|
|
+#include "socket.h"
|
|
+#include "packets.h"
|
|
+#include "timers.h"
|
|
+#include "hashtables.h"
|
|
+#include "peer.h"
|
|
+#include "uapi.h"
|
|
+
|
|
+static int clear_peer_endpoint_src(struct wireguard_peer *peer, void *data)
|
|
+{
|
|
+ socket_clear_peer_endpoint_src(peer);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int set_device_port(struct wireguard_device *wg, u16 port)
|
|
+{
|
|
+ socket_uninit(wg);
|
|
+ wg->incoming_port = port;
|
|
+ if (!(netdev_pub(wg)->flags & IFF_UP))
|
|
+ return 0;
|
|
+ peer_for_each_unlocked(wg, clear_peer_endpoint_src, NULL);
|
|
+ return socket_init(wg);
|
|
+}
|
|
+
|
|
+static int set_ipmask(struct wireguard_peer *peer, void __user *user_ipmask)
|
|
+{
|
|
+ int ret = -EINVAL;
|
|
+ struct wgipmask in_ipmask;
|
|
+
|
|
+ if (copy_from_user(&in_ipmask, user_ipmask, sizeof(in_ipmask)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ if (in_ipmask.family == AF_INET && in_ipmask.cidr <= 32)
|
|
+ ret = routing_table_insert_v4(&peer->device->peer_routing_table, &in_ipmask.ip4, in_ipmask.cidr, peer);
|
|
+ else if (in_ipmask.family == AF_INET6 && in_ipmask.cidr <= 128)
|
|
+ ret = routing_table_insert_v6(&peer->device->peer_routing_table, &in_ipmask.ip6, in_ipmask.cidr, peer);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const u8 zeros[WG_KEY_LEN] = { 0 };
|
|
+
|
|
+static int set_peer(struct wireguard_device *wg, void __user *user_peer, size_t *len)
|
|
+{
|
|
+ int ret = 0;
|
|
+ size_t i;
|
|
+ struct wgpeer in_peer;
|
|
+ void __user *user_ipmask;
|
|
+ struct wireguard_peer *peer = NULL;
|
|
+
|
|
+ if (copy_from_user(&in_peer, user_peer, sizeof(in_peer)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ if (!memcmp(zeros, in_peer.public_key, NOISE_PUBLIC_KEY_LEN))
|
|
+ return -EINVAL; /* Can't add a peer with no public key. */
|
|
+
|
|
+ peer = pubkey_hashtable_lookup(&wg->peer_hashtable, in_peer.public_key);
|
|
+ if (!peer) { /* Peer doesn't exist yet. Add a new one. */
|
|
+ if (in_peer.flags & WGPEER_REMOVE_ME)
|
|
+ return -ENODEV; /* Tried to remove a non existing peer. */
|
|
+ peer = peer_rcu_get(peer_create(wg, in_peer.public_key));
|
|
+ if (!peer)
|
|
+ return -ENOMEM;
|
|
+ if (netdev_pub(wg)->flags & IFF_UP)
|
|
+ timers_init_peer(peer);
|
|
+ }
|
|
+
|
|
+ if (in_peer.flags & WGPEER_REMOVE_ME) {
|
|
+ peer_put(peer);
|
|
+ peer_remove(peer);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (in_peer.endpoint.addr.sa_family == AF_INET || in_peer.endpoint.addr.sa_family == AF_INET6) {
|
|
+ struct endpoint endpoint = { 0 };
|
|
+ memcpy(&endpoint, &in_peer.endpoint, sizeof(in_peer.endpoint));
|
|
+ socket_set_peer_endpoint(peer, &endpoint);
|
|
+ }
|
|
+
|
|
+ if (in_peer.flags & WGPEER_REPLACE_IPMASKS)
|
|
+ routing_table_remove_by_peer(&wg->peer_routing_table, peer);
|
|
+ for (i = 0, user_ipmask = user_peer + sizeof(struct wgpeer); i < in_peer.num_ipmasks; ++i, user_ipmask += sizeof(struct wgipmask)) {
|
|
+ ret = set_ipmask(peer, user_ipmask);
|
|
+ if (ret)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (in_peer.persistent_keepalive_interval != (u16)-1) {
|
|
+ const bool send_keepalive = !peer->persistent_keepalive_interval && in_peer.persistent_keepalive_interval && netdev_pub(wg)->flags & IFF_UP;
|
|
+ peer->persistent_keepalive_interval = (unsigned long)in_peer.persistent_keepalive_interval * HZ;
|
|
+ if (send_keepalive)
|
|
+ packet_send_keepalive(peer);
|
|
+ }
|
|
+
|
|
+ if (netdev_pub(wg)->flags & IFF_UP)
|
|
+ packet_send_queue(peer);
|
|
+
|
|
+ peer_put(peer);
|
|
+
|
|
+out:
|
|
+ if (!ret)
|
|
+ *len = sizeof(struct wgpeer) + (in_peer.num_ipmasks * sizeof(struct wgipmask));
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int config_set_device(struct wireguard_device *wg, void __user *user_device)
|
|
+{
|
|
+ int ret = 0;
|
|
+ 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);
|
|
+
|
|
+ mutex_lock(&wg->device_update_lock);
|
|
+
|
|
+ if (copy_from_user(&in_device, user_device, sizeof(in_device))) {
|
|
+ ret = -EFAULT;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (in_device.fwmark || (!in_device.fwmark && (in_device.flags & WGDEVICE_REMOVE_FWMARK))) {
|
|
+ wg->fwmark = in_device.fwmark;
|
|
+ peer_for_each_unlocked(wg, clear_peer_endpoint_src, NULL);
|
|
+ }
|
|
+
|
|
+ if (in_device.port) {
|
|
+ ret = set_device_port(wg, in_device.port);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (in_device.flags & WGDEVICE_REPLACE_PEERS)
|
|
+ peer_remove_all(wg);
|
|
+
|
|
+ if (in_device.flags & WGDEVICE_REMOVE_PRIVATE_KEY) {
|
|
+ noise_set_static_identity_private_key(&wg->static_identity, NULL);
|
|
+ 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.flags & WGDEVICE_REMOVE_PRESHARED_KEY) {
|
|
+ noise_set_static_identity_preshared_key(&wg->static_identity, NULL);
|
|
+ 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);
|
|
+ if (ret)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ mutex_unlock(&wg->device_update_lock);
|
|
+ memzero_explicit(&in_device.private_key, NOISE_PUBLIC_KEY_LEN);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+struct data_remaining {
|
|
+ void __user *data;
|
|
+ size_t out_len;
|
|
+ size_t count;
|
|
+};
|
|
+
|
|
+static inline int use_data(struct data_remaining *data, size_t size)
|
|
+{
|
|
+ if (data->out_len < size)
|
|
+ return -EMSGSIZE;
|
|
+ data->out_len -= size;
|
|
+ data->data += size;
|
|
+ ++data->count;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int calculate_ipmasks_size(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family)
|
|
+{
|
|
+ size_t *count = ctx;
|
|
+ *count += sizeof(struct wgipmask);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static size_t calculate_peers_size(struct wireguard_device *wg)
|
|
+{
|
|
+ size_t len = peer_total_count(wg) * sizeof(struct wgpeer);
|
|
+ routing_table_walk_ips(&wg->peer_routing_table, &len, calculate_ipmasks_size);
|
|
+ return len;
|
|
+}
|
|
+
|
|
+static int populate_ipmask(void *ctx, union nf_inet_addr ip, u8 cidr, int family)
|
|
+{
|
|
+ int ret;
|
|
+ struct data_remaining *data = ctx;
|
|
+ void __user *uipmask = data->data;
|
|
+ struct wgipmask out_ipmask;
|
|
+
|
|
+ memset(&out_ipmask, 0, sizeof(struct wgipmask));
|
|
+
|
|
+ ret = use_data(data, sizeof(struct wgipmask));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ out_ipmask.cidr = cidr;
|
|
+ out_ipmask.family = family;
|
|
+ if (family == AF_INET)
|
|
+ out_ipmask.ip4 = ip.in;
|
|
+ else if (family == AF_INET6)
|
|
+ out_ipmask.ip6 = ip.in6;
|
|
+
|
|
+ if (copy_to_user(uipmask, &out_ipmask, sizeof(out_ipmask)))
|
|
+ ret = -EFAULT;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int populate_peer(struct wireguard_peer *peer, void *ctx)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct data_remaining *data = ctx;
|
|
+ void __user *upeer = data->data;
|
|
+ struct wgpeer out_peer;
|
|
+ struct data_remaining ipmasks_data = { NULL };
|
|
+
|
|
+ memset(&out_peer, 0, sizeof(struct wgpeer));
|
|
+
|
|
+ ret = use_data(data, sizeof(struct wgpeer));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ memcpy(out_peer.public_key, peer->handshake.remote_static, NOISE_PUBLIC_KEY_LEN);
|
|
+ read_lock_bh(&peer->endpoint_lock);
|
|
+ if (peer->endpoint.addr.sa_family == AF_INET)
|
|
+ out_peer.endpoint.addr4 = peer->endpoint.addr4;
|
|
+ else if (peer->endpoint.addr.sa_family == AF_INET6)
|
|
+ out_peer.endpoint.addr6 = peer->endpoint.addr6;
|
|
+ read_unlock_bh(&peer->endpoint_lock);
|
|
+ out_peer.last_handshake_time = peer->walltime_last_handshake;
|
|
+ out_peer.tx_bytes = peer->tx_bytes;
|
|
+ out_peer.rx_bytes = peer->rx_bytes;
|
|
+ out_peer.persistent_keepalive_interval = (u16)(peer->persistent_keepalive_interval / HZ);
|
|
+
|
|
+ ipmasks_data.out_len = data->out_len;
|
|
+ ipmasks_data.data = data->data;
|
|
+ ret = routing_table_walk_ips_by_peer_sleepable(&peer->device->peer_routing_table, &ipmasks_data, peer, populate_ipmask);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ data->out_len = ipmasks_data.out_len;
|
|
+ data->data = ipmasks_data.data;
|
|
+ out_peer.num_ipmasks = ipmasks_data.count;
|
|
+
|
|
+ if (copy_to_user(upeer, &out_peer, sizeof(out_peer)))
|
|
+ ret = -EFAULT;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int config_get_device(struct wireguard_device *wg, void __user *udevice)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct net_device *dev = netdev_pub(wg);
|
|
+ struct data_remaining peer_data = { NULL };
|
|
+ struct wgdevice out_device;
|
|
+ struct wgdevice in_device;
|
|
+
|
|
+ BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN);
|
|
+ BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN);
|
|
+
|
|
+ memset(&out_device, 0, sizeof(struct wgdevice));
|
|
+
|
|
+ mutex_lock(&wg->device_update_lock);
|
|
+
|
|
+ if (!udevice) {
|
|
+ ret = calculate_peers_size(wg);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (copy_from_user(&in_device, udevice, sizeof(in_device))) {
|
|
+ ret = -EFAULT;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ out_device.port = wg->incoming_port;
|
|
+ out_device.fwmark = wg->fwmark;
|
|
+ strncpy(out_device.interface, dev->name, IFNAMSIZ - 1);
|
|
+ out_device.interface[IFNAMSIZ - 1] = 0;
|
|
+
|
|
+ down_read(&wg->static_identity.lock);
|
|
+ if (wg->static_identity.has_identity) {
|
|
+ memcpy(out_device.private_key, wg->static_identity.static_private, WG_KEY_LEN);
|
|
+ memcpy(out_device.public_key, wg->static_identity.static_public, WG_KEY_LEN);
|
|
+ memcpy(out_device.preshared_key, wg->static_identity.preshared_key, WG_KEY_LEN);
|
|
+ }
|
|
+ up_read(&wg->static_identity.lock);
|
|
+
|
|
+ peer_data.out_len = in_device.peers_size;
|
|
+ peer_data.data = udevice + sizeof(struct wgdevice);
|
|
+ ret = peer_for_each_unlocked(wg, populate_peer, &peer_data);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+ out_device.num_peers = peer_data.count;
|
|
+
|
|
+ if (copy_to_user(udevice, &out_device, sizeof(out_device)))
|
|
+ ret = -EFAULT;
|
|
+
|
|
+out:
|
|
+ mutex_unlock(&wg->device_update_lock);
|
|
+ memzero_explicit(&out_device.private_key, NOISE_PUBLIC_KEY_LEN);
|
|
+ return ret;
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/cookie.c
|
|
@@ -0,0 +1,215 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "cookie.h"
|
|
+#include "peer.h"
|
|
+#include "device.h"
|
|
+#include "messages.h"
|
|
+#include "crypto/blake2s.h"
|
|
+#include "crypto/chacha20poly1305.h"
|
|
+
|
|
+#include <linux/jiffies.h>
|
|
+#include <net/ipv6.h>
|
|
+#include <crypto/algapi.h>
|
|
+
|
|
+int cookie_checker_init(struct cookie_checker *checker, struct wireguard_device *wg)
|
|
+{
|
|
+ int ret = ratelimiter_init(&checker->ratelimiter, wg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ init_rwsem(&checker->secret_lock);
|
|
+ checker->secret_birthdate = get_jiffies_64();
|
|
+ get_random_bytes(checker->secret, NOISE_HASH_LEN);
|
|
+ checker->device = wg;
|
|
+ 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);
|
|
+}
|
|
+
|
|
+void cookie_init(struct cookie *cookie)
|
|
+{
|
|
+ memset(cookie, 0, sizeof(struct cookie));
|
|
+ init_rwsem(&cookie->lock);
|
|
+}
|
|
+
|
|
+static void compute_mac1(u8 mac1[COOKIE_LEN], const void *message, size_t len, const u8 pubkey[NOISE_PUBLIC_KEY_LEN], const u8 psk[NOISE_SYMMETRIC_KEY_LEN])
|
|
+{
|
|
+ struct blake2s_state state;
|
|
+ len = len - sizeof(struct message_macs) + offsetof(struct message_macs, mac1);
|
|
+
|
|
+ if (psk)
|
|
+ blake2s_init_key(&state, COOKIE_LEN, psk, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ else
|
|
+ blake2s_init(&state, COOKIE_LEN);
|
|
+ blake2s_update(&state, pubkey, NOISE_PUBLIC_KEY_LEN);
|
|
+ blake2s_update(&state, message, len);
|
|
+ blake2s_final(&state, mac1, COOKIE_LEN);
|
|
+}
|
|
+
|
|
+static void compute_mac2(u8 mac2[COOKIE_LEN], const void *message, size_t len, const u8 cookie[COOKIE_LEN])
|
|
+{
|
|
+ len = len - sizeof(struct message_macs) + offsetof(struct message_macs, mac2);
|
|
+ blake2s(mac2, message, cookie, COOKIE_LEN, len, COOKIE_LEN);
|
|
+}
|
|
+
|
|
+static void make_cookie(u8 cookie[COOKIE_LEN], struct sk_buff *skb, struct cookie_checker *checker)
|
|
+{
|
|
+ struct blake2s_state state;
|
|
+
|
|
+ if (!time_is_after_jiffies64(checker->secret_birthdate + COOKIE_SECRET_MAX_AGE)) {
|
|
+ down_write(&checker->secret_lock);
|
|
+ checker->secret_birthdate = get_jiffies_64();
|
|
+ get_random_bytes(checker->secret, NOISE_HASH_LEN);
|
|
+ up_write(&checker->secret_lock);
|
|
+ }
|
|
+
|
|
+ down_read(&checker->secret_lock);
|
|
+
|
|
+ blake2s_init_key(&state, COOKIE_LEN, checker->secret, NOISE_HASH_LEN);
|
|
+ if (ip_hdr(skb)->version == 4)
|
|
+ blake2s_update(&state, (u8 *)&ip_hdr(skb)->saddr, sizeof(struct in_addr));
|
|
+ else if (ip_hdr(skb)->version == 6)
|
|
+ blake2s_update(&state, (u8 *)&ipv6_hdr(skb)->saddr, sizeof(struct in6_addr));
|
|
+ blake2s_update(&state, (u8 *)&udp_hdr(skb)->source, sizeof(__be16));
|
|
+ blake2s_final(&state, cookie, COOKIE_LEN);
|
|
+
|
|
+ up_read(&checker->secret_lock);
|
|
+}
|
|
+
|
|
+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)
|
|
+{
|
|
+ u8 computed_mac[COOKIE_LEN];
|
|
+ u8 cookie[COOKIE_LEN];
|
|
+ enum cookie_mac_state ret;
|
|
+ struct message_macs *macs = (struct message_macs *)((u8 *)data_start + data_len - sizeof(struct message_macs));
|
|
+
|
|
+ ret = INVALID_MAC;
|
|
+ down_read(&checker->device->static_identity.lock);
|
|
+ if (unlikely(!checker->device->static_identity.has_identity)) {
|
|
+ up_read(&checker->device->static_identity.lock);
|
|
+ goto out;
|
|
+ }
|
|
+ compute_mac1(computed_mac, data_start, data_len, checker->device->static_identity.static_public, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL);
|
|
+ up_read(&checker->device->static_identity.lock);
|
|
+ if (crypto_memneq(computed_mac, macs->mac1, COOKIE_LEN))
|
|
+ goto out;
|
|
+
|
|
+ ret = VALID_MAC_BUT_NO_COOKIE;
|
|
+
|
|
+ if (!check_cookie)
|
|
+ goto out;
|
|
+
|
|
+ make_cookie(cookie, skb, checker);
|
|
+
|
|
+ compute_mac2(computed_mac, data_start, data_len, cookie);
|
|
+ if (crypto_memneq(computed_mac, macs->mac2, COOKIE_LEN))
|
|
+ goto out;
|
|
+
|
|
+ ret = VALID_MAC_WITH_COOKIE_BUT_RATELIMITED;
|
|
+ if (!ratelimiter_allow(&checker->ratelimiter, skb))
|
|
+ goto out;
|
|
+
|
|
+ ret = VALID_MAC_WITH_COOKIE;
|
|
+
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void cookie_add_mac_to_packet(void *message, size_t len, struct wireguard_peer *peer)
|
|
+{
|
|
+ struct message_macs *macs = (struct message_macs *)((u8 *)message + len - sizeof(struct message_macs));
|
|
+
|
|
+ down_read(&peer->device->static_identity.lock);
|
|
+ if (unlikely(!peer->device->static_identity.has_identity)) {
|
|
+ memset(macs, 0, sizeof(struct message_macs));
|
|
+ up_read(&peer->device->static_identity.lock);
|
|
+ return;
|
|
+ }
|
|
+ compute_mac1(macs->mac1, message, len, peer->handshake.remote_static, peer->device->static_identity.has_psk ? peer->device->static_identity.preshared_key : NULL);
|
|
+ up_read(&peer->device->static_identity.lock);
|
|
+
|
|
+ down_write(&peer->latest_cookie.lock);
|
|
+ memcpy(peer->latest_cookie.last_mac1_sent, macs->mac1, COOKIE_LEN);
|
|
+ peer->latest_cookie.have_sent_mac1 = true;
|
|
+ up_write(&peer->latest_cookie.lock);
|
|
+
|
|
+ down_read(&peer->latest_cookie.lock);
|
|
+ if (peer->latest_cookie.is_valid && time_is_after_jiffies64(peer->latest_cookie.birthdate + COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY))
|
|
+ compute_mac2(macs->mac2, message, len, peer->latest_cookie.cookie);
|
|
+ else
|
|
+ memset(macs->mac2, 0, COOKIE_LEN);
|
|
+ up_read(&peer->latest_cookie.lock);
|
|
+}
|
|
+
|
|
+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));
|
|
+ u8 cookie[COOKIE_LEN];
|
|
+
|
|
+ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE);
|
|
+ dst->receiver_index = index;
|
|
+ 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);
|
|
+ xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN, macs->mac1, COOKIE_LEN, dst->nonce, checker->cookie_encryption_key);
|
|
+}
|
|
+
|
|
+void cookie_message_consume(struct message_handshake_cookie *src, struct wireguard_device *wg)
|
|
+{
|
|
+ u8 cookie[COOKIE_LEN];
|
|
+ struct index_hashtable_entry *entry;
|
|
+ bool ret;
|
|
+
|
|
+ entry = index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_HANDSHAKE | INDEX_HASHTABLE_KEYPAIR, src->receiver_index);
|
|
+ if (!unlikely(entry))
|
|
+ return;
|
|
+
|
|
+ down_read(&entry->peer->latest_cookie.lock);
|
|
+ if (unlikely(!entry->peer->latest_cookie.have_sent_mac1)) {
|
|
+ up_read(&entry->peer->latest_cookie.lock);
|
|
+ goto out;
|
|
+ }
|
|
+ ret = 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);
|
|
+ up_read(&entry->peer->latest_cookie.lock);
|
|
+
|
|
+ if (ret) {
|
|
+ down_write(&entry->peer->latest_cookie.lock);
|
|
+ memcpy(entry->peer->latest_cookie.cookie, cookie, COOKIE_LEN);
|
|
+ entry->peer->latest_cookie.birthdate = get_jiffies_64();
|
|
+ entry->peer->latest_cookie.is_valid = true;
|
|
+ entry->peer->latest_cookie.have_sent_mac1 = false;
|
|
+ up_write(&entry->peer->latest_cookie.lock);
|
|
+ } else
|
|
+ net_dbg_ratelimited("Could not decrypt invalid cookie response\n");
|
|
+
|
|
+out:
|
|
+ peer_put(entry->peer);
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/data.c
|
|
@@ -0,0 +1,493 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "noise.h"
|
|
+#include "device.h"
|
|
+#include "peer.h"
|
|
+#include "messages.h"
|
|
+#include "packets.h"
|
|
+#include "hashtables.h"
|
|
+
|
|
+#include <linux/rcupdate.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/bitmap.h>
|
|
+#include <linux/scatterlist.h>
|
|
+#include <net/ip_tunnels.h>
|
|
+#include <net/xfrm.h>
|
|
+#include <crypto/algapi.h>
|
|
+
|
|
+struct encryption_skb_cb {
|
|
+ u8 ds;
|
|
+ u8 num_frags;
|
|
+ unsigned int plaintext_len, trailer_len;
|
|
+ struct sk_buff *trailer;
|
|
+ u64 nonce;
|
|
+};
|
|
+
|
|
+struct encryption_ctx {
|
|
+ struct padata_priv padata;
|
|
+ struct sk_buff_head queue;
|
|
+ packet_create_data_callback_t callback;
|
|
+ struct wireguard_peer *peer;
|
|
+ struct noise_keypair *keypair;
|
|
+};
|
|
+
|
|
+struct decryption_ctx {
|
|
+ struct padata_priv padata;
|
|
+ struct sk_buff *skb;
|
|
+ packet_consume_data_callback_t callback;
|
|
+ struct noise_keypair *keypair;
|
|
+ struct endpoint endpoint;
|
|
+ u64 nonce;
|
|
+ int ret;
|
|
+ u8 num_frags;
|
|
+};
|
|
+
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+static struct kmem_cache *encryption_ctx_cache __read_mostly;
|
|
+static struct kmem_cache *decryption_ctx_cache __read_mostly;
|
|
+
|
|
+int packet_init_data_caches(void)
|
|
+{
|
|
+ BUILD_BUG_ON(sizeof(struct encryption_skb_cb) > sizeof(((struct sk_buff *)0)->cb));
|
|
+ encryption_ctx_cache = kmem_cache_create("wireguard_encryption_ctx", sizeof(struct encryption_ctx), 0, 0, NULL);
|
|
+ if (!encryption_ctx_cache)
|
|
+ return -ENOMEM;
|
|
+ decryption_ctx_cache = kmem_cache_create("wireguard_decryption_ctx", sizeof(struct decryption_ctx), 0, 0, NULL);
|
|
+ if (!decryption_ctx_cache) {
|
|
+ kmem_cache_destroy(encryption_ctx_cache);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void packet_deinit_data_caches(void)
|
|
+{
|
|
+ kmem_cache_destroy(encryption_ctx_cache);
|
|
+ kmem_cache_destroy(decryption_ctx_cache);
|
|
+}
|
|
+#endif
|
|
+
|
|
+/* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */
|
|
+static inline bool counter_validate(union noise_counter *counter, u64 their_counter)
|
|
+{
|
|
+ bool ret = false;
|
|
+ unsigned long index, index_current, top, i;
|
|
+ spin_lock_bh(&counter->receive.lock);
|
|
+
|
|
+ if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 || their_counter >= REJECT_AFTER_MESSAGES))
|
|
+ goto out;
|
|
+
|
|
+ ++their_counter;
|
|
+
|
|
+ if (unlikely((COUNTER_WINDOW_SIZE + their_counter) < counter->receive.counter))
|
|
+ goto out;
|
|
+
|
|
+ index = their_counter >> ilog2(COUNTER_REDUNDANT_BITS);
|
|
+
|
|
+ if (likely(their_counter > counter->receive.counter)) {
|
|
+ index_current = counter->receive.counter >> ilog2(COUNTER_REDUNDANT_BITS);
|
|
+ top = min_t(unsigned long, index - index_current, COUNTER_BITS_TOTAL / BITS_PER_LONG);
|
|
+ for (i = 1; i <= top; ++i)
|
|
+ counter->receive.backtrack[(i + index_current) & ((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0;
|
|
+ counter->receive.counter = their_counter;
|
|
+ }
|
|
+
|
|
+ index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1;
|
|
+ ret = !test_and_set_bit(their_counter & (COUNTER_REDUNDANT_BITS - 1), &counter->receive.backtrack[index]);
|
|
+
|
|
+out:
|
|
+ spin_unlock_bh(&counter->receive.lock);
|
|
+ return ret;
|
|
+}
|
|
+#include "selftest/counter.h"
|
|
+
|
|
+static inline unsigned int skb_padding(struct sk_buff *skb)
|
|
+{
|
|
+ /* We do this modulo business with the MTU, just in case the networking layer
|
|
+ * gives us a packet that's bigger than the MTU. Now that we support GSO, this
|
|
+ * shouldn't be a real problem, and this can likely be removed. But, caution! */
|
|
+ unsigned int last_unit = skb->len % skb->dev->mtu;
|
|
+ unsigned int padded_size = (last_unit + MESSAGE_PADDING_MULTIPLE - 1) & ~(MESSAGE_PADDING_MULTIPLE - 1);
|
|
+ if (padded_size > skb->dev->mtu)
|
|
+ padded_size = skb->dev->mtu;
|
|
+ return padded_size - last_unit;
|
|
+}
|
|
+
|
|
+static inline void skb_reset(struct sk_buff *skb)
|
|
+{
|
|
+ skb_scrub_packet(skb, false);
|
|
+ memset(&skb->headers_start, 0, offsetof(struct sk_buff, headers_end) - offsetof(struct sk_buff, headers_start));
|
|
+ skb->queue_mapping = 0;
|
|
+ skb->nohdr = 0;
|
|
+ skb->peeked = 0;
|
|
+ skb->mac_len = 0;
|
|
+ skb->dev = NULL;
|
|
+#ifdef CONFIG_NET_SCHED
|
|
+ skb->tc_index = 0;
|
|
+ skb_reset_tc(skb);
|
|
+#endif
|
|
+ skb->hdr_len = skb_headroom(skb);
|
|
+ skb_reset_mac_header(skb);
|
|
+ skb_reset_network_header(skb);
|
|
+ skb_probe_transport_header(skb, 0);
|
|
+}
|
|
+
|
|
+static inline void skb_encrypt(struct sk_buff *skb, struct noise_keypair *keypair, bool have_simd)
|
|
+{
|
|
+ struct encryption_skb_cb *cb = (struct encryption_skb_cb *)skb->cb;
|
|
+ struct scatterlist sg[cb->num_frags]; /* This should be bound to at most 128 by the caller. */
|
|
+ struct message_data *header;
|
|
+
|
|
+ /* We have to remember to add the checksum to the innerpacket, in case the receiver forwards it. */
|
|
+ if (likely(!skb_checksum_setup(skb, true)))
|
|
+ skb_checksum_help(skb);
|
|
+
|
|
+ /* Only after checksumming can we safely add on the padding at the end and the header. */
|
|
+ header = (struct message_data *)skb_push(skb, sizeof(struct message_data));
|
|
+ header->header.type = cpu_to_le32(MESSAGE_DATA);
|
|
+ header->key_idx = keypair->remote_index;
|
|
+ header->counter = cpu_to_le64(cb->nonce);
|
|
+ pskb_put(skb, cb->trailer, cb->trailer_len);
|
|
+
|
|
+ /* Now we can encrypt the scattergather segments */
|
|
+ sg_init_table(sg, cb->num_frags);
|
|
+ skb_to_sgvec(skb, sg, sizeof(struct message_data), noise_encrypted_len(cb->plaintext_len));
|
|
+ chacha20poly1305_encrypt_sg(sg, sg, cb->plaintext_len, NULL, 0, cb->nonce, keypair->sending.key, have_simd);
|
|
+}
|
|
+
|
|
+static inline bool skb_decrypt(struct sk_buff *skb, u8 num_frags, u64 nonce, struct noise_symmetric_key *key)
|
|
+{
|
|
+ struct scatterlist sg[num_frags]; /* This should be bound to at most 128 by the caller. */
|
|
+
|
|
+ if (unlikely(!key))
|
|
+ return false;
|
|
+
|
|
+ if (unlikely(!key->is_valid || time_is_before_eq_jiffies64(key->birthdate + REJECT_AFTER_TIME) || key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) {
|
|
+ key->is_valid = false;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ sg_init_table(sg, num_frags);
|
|
+ skb_to_sgvec(skb, sg, 0, skb->len);
|
|
+
|
|
+ if (!chacha20poly1305_decrypt_sg(sg, sg, skb->len, NULL, 0, nonce, key->key))
|
|
+ return false;
|
|
+
|
|
+ return pskb_trim(skb, skb->len - noise_encrypted_len(0)) == 0;
|
|
+}
|
|
+
|
|
+static inline bool get_encryption_nonce(u64 *nonce, struct noise_symmetric_key *key)
|
|
+{
|
|
+ if (unlikely(!key))
|
|
+ return false;
|
|
+
|
|
+ if (unlikely(!key->is_valid || time_is_before_eq_jiffies64(key->birthdate + REJECT_AFTER_TIME))) {
|
|
+ key->is_valid = false;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ *nonce = atomic64_inc_return(&key->counter.counter) - 1;
|
|
+ if (*nonce >= REJECT_AFTER_MESSAGES) {
|
|
+ key->is_valid = false;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static inline void queue_encrypt_reset(struct sk_buff_head *queue, struct noise_keypair *keypair)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+ bool have_simd = chacha20poly1305_init_simd();
|
|
+ skb_queue_walk(queue, skb) {
|
|
+ skb_encrypt(skb, keypair, have_simd);
|
|
+ skb_reset(skb);
|
|
+ }
|
|
+ chacha20poly1305_deinit_simd(have_simd);
|
|
+ noise_keypair_put(keypair);
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+static void do_encryption(struct padata_priv *padata)
|
|
+{
|
|
+ struct encryption_ctx *ctx = container_of(padata, struct encryption_ctx, padata);
|
|
+
|
|
+ queue_encrypt_reset(&ctx->queue, ctx->keypair);
|
|
+ padata_do_serial(padata);
|
|
+}
|
|
+
|
|
+static void finish_encryption(struct padata_priv *padata)
|
|
+{
|
|
+ struct encryption_ctx *ctx = container_of(padata, struct encryption_ctx, padata);
|
|
+
|
|
+ ctx->callback(&ctx->queue, ctx->peer);
|
|
+ atomic_dec(&ctx->peer->parallel_encryption_inflight);
|
|
+ peer_put(ctx->peer);
|
|
+ kmem_cache_free(encryption_ctx_cache, ctx);
|
|
+}
|
|
+
|
|
+static inline int start_encryption(struct padata_instance *padata, struct padata_priv *priv, int cb_cpu)
|
|
+{
|
|
+ memset(priv, 0, sizeof(struct padata_priv));
|
|
+ priv->parallel = do_encryption;
|
|
+ priv->serial = finish_encryption;
|
|
+ return padata_do_parallel(padata, priv, cb_cpu);
|
|
+}
|
|
+
|
|
+static inline unsigned int choose_cpu(__le32 key)
|
|
+{
|
|
+ unsigned int cpu_index, cpu, cb_cpu;
|
|
+
|
|
+ /* This ensures that packets encrypted to the same key are sent in-order. */
|
|
+ cpu_index = ((__force unsigned int)key) % cpumask_weight(cpu_online_mask);
|
|
+ cb_cpu = cpumask_first(cpu_online_mask);
|
|
+ for (cpu = 0; cpu < cpu_index; ++cpu)
|
|
+ cb_cpu = cpumask_next(cb_cpu, cpu_online_mask);
|
|
+
|
|
+ return cb_cpu;
|
|
+}
|
|
+#endif
|
|
+
|
|
+int packet_create_data(struct sk_buff_head *queue, struct wireguard_peer *peer, packet_create_data_callback_t callback)
|
|
+{
|
|
+ int ret = -ENOKEY;
|
|
+ struct noise_keypair *keypair;
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ keypair = noise_keypair_get(rcu_dereference(peer->keypairs.current_keypair));
|
|
+ if (unlikely(!keypair))
|
|
+ goto err_rcu;
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ skb_queue_walk(queue, skb) {
|
|
+ struct encryption_skb_cb *cb = (struct encryption_skb_cb *)skb->cb;
|
|
+ unsigned int padding_len, num_frags;
|
|
+
|
|
+ if (unlikely(!get_encryption_nonce(&cb->nonce, &keypair->sending)))
|
|
+ goto err;
|
|
+
|
|
+ padding_len = skb_padding(skb);
|
|
+ cb->trailer_len = padding_len + noise_encrypted_len(0);
|
|
+ cb->plaintext_len = skb->len + padding_len;
|
|
+
|
|
+ /* Store the ds bit in the cb */
|
|
+ cb->ds = ip_tunnel_ecn_encap(0 /* No outer TOS: no leak. TODO: should we use flowi->tos as outer? */, ip_hdr(skb), skb);
|
|
+
|
|
+ /* Expand data section to have room for padding and auth tag */
|
|
+ ret = skb_cow_data(skb, cb->trailer_len, &cb->trailer);
|
|
+ if (unlikely(ret < 0))
|
|
+ goto err;
|
|
+ num_frags = ret;
|
|
+ ret = -ENOMEM;
|
|
+ if (unlikely(num_frags > 128))
|
|
+ goto err;
|
|
+ cb->num_frags = num_frags;
|
|
+
|
|
+ /* Set the padding to zeros, and make sure it and the auth tag are part of the skb */
|
|
+ memset(skb_tail_pointer(cb->trailer), 0, padding_len);
|
|
+
|
|
+ /* Expand head section to have room for our header and the network stack's headers. */
|
|
+ ret = skb_cow_head(skb, DATA_PACKET_HEAD_ROOM);
|
|
+ if (unlikely(ret < 0))
|
|
+ goto err;
|
|
+
|
|
+ /* After the first time through the loop, if we've suceeded with a legitimate nonce,
|
|
+ * then we don't want a -ENOKEY error if subsequent nonces fail. Rather, if this
|
|
+ * condition arises, we simply want error out hard, and drop the entire queue. This
|
|
+ * is partially lazy programming and TODO: this could be made to only requeue the
|
|
+ * ones that had no nonce. But I'm not sure it's worth the added complexity, given
|
|
+ * how rarely that condition should arise. */
|
|
+ ret = -EPIPE;
|
|
+ }
|
|
+
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ if ((skb_queue_len(queue) > 1 || queue->next->len > 256 || atomic_read(&peer->parallel_encryption_inflight) > 0) && cpumask_weight(cpu_online_mask) > 1) {
|
|
+ unsigned int cpu = choose_cpu(keypair->remote_index);
|
|
+ struct encryption_ctx *ctx = kmem_cache_alloc(encryption_ctx_cache, GFP_ATOMIC);
|
|
+ if (!ctx)
|
|
+ goto serial_encrypt;
|
|
+ skb_queue_head_init(&ctx->queue);
|
|
+ skb_queue_splice_init(queue, &ctx->queue);
|
|
+ ctx->callback = callback;
|
|
+ ctx->keypair = keypair;
|
|
+ ctx->peer = peer_rcu_get(peer);
|
|
+ ret = -EBUSY;
|
|
+ if (unlikely(!ctx->peer))
|
|
+ goto err_parallel;
|
|
+ atomic_inc(&peer->parallel_encryption_inflight);
|
|
+ ret = start_encryption(peer->device->parallel_send, &ctx->padata, cpu);
|
|
+ if (unlikely(ret < 0)) {
|
|
+ atomic_dec(&peer->parallel_encryption_inflight);
|
|
+ peer_put(ctx->peer);
|
|
+err_parallel:
|
|
+ skb_queue_splice(&ctx->queue, queue);
|
|
+ kmem_cache_free(encryption_ctx_cache, ctx);
|
|
+ goto err;
|
|
+ }
|
|
+ } else
|
|
+serial_encrypt:
|
|
+#endif
|
|
+ {
|
|
+ queue_encrypt_reset(queue, keypair);
|
|
+ callback(queue, peer);
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+err:
|
|
+ noise_keypair_put(keypair);
|
|
+ return ret;
|
|
+err_rcu:
|
|
+ rcu_read_unlock();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void begin_decrypt_packet(struct decryption_ctx *ctx)
|
|
+{
|
|
+ if (unlikely(!skb_decrypt(ctx->skb, ctx->num_frags, ctx->nonce, &ctx->keypair->receiving)))
|
|
+ goto err;
|
|
+
|
|
+ skb_reset(ctx->skb);
|
|
+ ctx->ret = 0;
|
|
+ return;
|
|
+
|
|
+err:
|
|
+ ctx->ret = -ENOKEY;
|
|
+ peer_put(ctx->keypair->entry.peer);
|
|
+}
|
|
+
|
|
+static void finish_decrypt_packet(struct decryption_ctx *ctx)
|
|
+{
|
|
+ struct noise_keypairs *keypairs;
|
|
+ bool used_new_key = false;
|
|
+ int ret = ctx->ret;
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ keypairs = &ctx->keypair->entry.peer->keypairs;
|
|
+ ret = counter_validate(&ctx->keypair->receiving.counter, ctx->nonce) ? 0 : -ERANGE;
|
|
+
|
|
+ if (likely(!ret))
|
|
+ used_new_key = noise_received_with_keypair(&ctx->keypair->entry.peer->keypairs, ctx->keypair);
|
|
+ else {
|
|
+ net_dbg_ratelimited("Packet has invalid nonce %Lu (max %Lu)\n", ctx->nonce, ctx->keypair->receiving.counter.receive.counter);
|
|
+ peer_put(ctx->keypair->entry.peer);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ noise_keypair_put(ctx->keypair);
|
|
+ ctx->callback(ctx->skb, ctx->keypair->entry.peer, &ctx->endpoint, used_new_key, 0);
|
|
+ return;
|
|
+
|
|
+err:
|
|
+ noise_keypair_put(ctx->keypair);
|
|
+ ctx->callback(ctx->skb, NULL, NULL, false, ret);
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+static void do_decryption(struct padata_priv *padata)
|
|
+{
|
|
+ struct decryption_ctx *ctx = container_of(padata, struct decryption_ctx, padata);
|
|
+ begin_decrypt_packet(ctx);
|
|
+ padata_do_serial(padata);
|
|
+}
|
|
+
|
|
+static void finish_decryption(struct padata_priv *padata)
|
|
+{
|
|
+ struct decryption_ctx *ctx = container_of(padata, struct decryption_ctx, padata);
|
|
+ finish_decrypt_packet(ctx);
|
|
+ kmem_cache_free(decryption_ctx_cache, ctx);
|
|
+}
|
|
+
|
|
+static inline int start_decryption(struct padata_instance *padata, struct padata_priv *priv, int cb_cpu)
|
|
+{
|
|
+ priv->parallel = do_decryption;
|
|
+ priv->serial = finish_decryption;
|
|
+ return padata_do_parallel(padata, priv, cb_cpu);
|
|
+}
|
|
+#endif
|
|
+
|
|
+void packet_consume_data(struct sk_buff *skb, size_t offset, struct wireguard_device *wg, packet_consume_data_callback_t callback)
|
|
+{
|
|
+ int ret;
|
|
+ struct endpoint endpoint;
|
|
+ unsigned int num_frags;
|
|
+ struct sk_buff *trailer;
|
|
+ struct message_data *header;
|
|
+ struct noise_keypair *keypair;
|
|
+ u64 nonce;
|
|
+ __le32 idx;
|
|
+
|
|
+ ret = socket_endpoint_from_skb(&endpoint, skb);
|
|
+ if (unlikely(ret < 0))
|
|
+ goto err;
|
|
+
|
|
+ ret = -ENOMEM;
|
|
+ if (unlikely(!pskb_may_pull(skb, offset + sizeof(struct message_data))))
|
|
+ goto err;
|
|
+
|
|
+ header = (struct message_data *)(skb->data + offset);
|
|
+ offset += sizeof(struct message_data);
|
|
+ skb_pull(skb, offset);
|
|
+
|
|
+ idx = header->key_idx;
|
|
+ nonce = le64_to_cpu(header->counter);
|
|
+
|
|
+ ret = skb_cow_data(skb, 0, &trailer);
|
|
+ if (unlikely(ret < 0))
|
|
+ goto err;
|
|
+ num_frags = ret;
|
|
+ ret = -ENOMEM;
|
|
+ if (unlikely(num_frags > 128))
|
|
+ goto err;
|
|
+ ret = -EINVAL;
|
|
+ rcu_read_lock();
|
|
+ keypair = noise_keypair_get((struct noise_keypair *)index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_KEYPAIR, idx));
|
|
+ rcu_read_unlock();
|
|
+ if (unlikely(!keypair))
|
|
+ goto err;
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ if (cpumask_weight(cpu_online_mask) > 1) {
|
|
+ unsigned int cpu = choose_cpu(idx);
|
|
+ struct decryption_ctx *ctx;
|
|
+
|
|
+ ret = -ENOMEM;
|
|
+ ctx = kmem_cache_alloc(decryption_ctx_cache, GFP_ATOMIC);
|
|
+ if (unlikely(!ctx))
|
|
+ goto err_peer;
|
|
+
|
|
+ ctx->skb = skb;
|
|
+ ctx->keypair = keypair;
|
|
+ ctx->callback = callback;
|
|
+ ctx->nonce = nonce;
|
|
+ ctx->num_frags = num_frags;
|
|
+ ctx->endpoint = endpoint;
|
|
+ ret = start_decryption(wg->parallel_receive, &ctx->padata, cpu);
|
|
+ if (unlikely(ret)) {
|
|
+ kmem_cache_free(decryption_ctx_cache, ctx);
|
|
+ goto err_peer;
|
|
+ }
|
|
+ } else
|
|
+#endif
|
|
+ {
|
|
+ struct decryption_ctx ctx = {
|
|
+ .skb = skb,
|
|
+ .keypair = keypair,
|
|
+ .callback = callback,
|
|
+ .nonce = nonce,
|
|
+ .num_frags = num_frags,
|
|
+ .endpoint = endpoint
|
|
+ };
|
|
+ begin_decrypt_packet(&ctx);
|
|
+ finish_decrypt_packet(&ctx);
|
|
+ }
|
|
+ return;
|
|
+
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+err_peer:
|
|
+ peer_put(keypair->entry.peer);
|
|
+ noise_keypair_put(keypair);
|
|
+#endif
|
|
+err:
|
|
+ callback(skb, NULL, NULL, false, ret);
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/device.c
|
|
@@ -0,0 +1,387 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "packets.h"
|
|
+#include "socket.h"
|
|
+#include "timers.h"
|
|
+#include "device.h"
|
|
+#include "config.h"
|
|
+#include "peer.h"
|
|
+#include "uapi.h"
|
|
+#include "messages.h"
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/rtnetlink.h>
|
|
+#include <linux/inet.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/inetdevice.h>
|
|
+#include <linux/if_arp.h>
|
|
+#include <linux/icmp.h>
|
|
+#include <linux/suspend.h>
|
|
+#include <net/icmp.h>
|
|
+#include <net/rtnetlink.h>
|
|
+#include <net/ip_tunnels.h>
|
|
+#include <net/addrconf.h>
|
|
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
|
|
+#include <net/netfilter/nf_conntrack.h>
|
|
+#include <net/netfilter/nf_nat_core.h>
|
|
+#endif
|
|
+
|
|
+static int open_peer(struct wireguard_peer *peer, void *data)
|
|
+{
|
|
+ timers_init_peer(peer);
|
|
+ packet_send_queue(peer);
|
|
+ if (peer->persistent_keepalive_interval)
|
|
+ packet_send_keepalive(peer);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int open(struct net_device *dev)
|
|
+{
|
|
+ int ret;
|
|
+ struct wireguard_device *wg = netdev_priv(dev);
|
|
+ struct inet6_dev *dev_v6 = __in6_dev_get(dev);
|
|
+ struct in_device *dev_v4 = __in_dev_get_rtnl(dev);
|
|
+
|
|
+ if (dev_v4) {
|
|
+ /* TODO: when we merge to mainline, put this check near the ip_rt_send_redirect
|
|
+ * call of ip_forward in net/ipv4/ip_forward.c, similar to the current secpath
|
|
+ * check, rather than turning it off like this. This is just a stop gap solution
|
|
+ * while we're an out of tree module. */
|
|
+ IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
|
|
+ IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false;
|
|
+ }
|
|
+ if (dev_v6)
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
|
+ dev_v6->addr_gen_mode = IN6_ADDR_GEN_MODE_NONE;
|
|
+#else
|
|
+ dev_v6->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_NONE;
|
|
+#endif
|
|
+
|
|
+ ret = socket_init(wg);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ peer_for_each(wg, open_peer, NULL);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int clear_noise_peer(struct wireguard_peer *peer, void *data)
|
|
+{
|
|
+ noise_handshake_clear(&peer->handshake);
|
|
+ noise_keypairs_clear(&peer->keypairs);
|
|
+ if (peer->timers_enabled)
|
|
+ del_timer(&peer->timer_kill_ephemerals);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
+static int suspending_clear_noise_peers(struct notifier_block *nb, unsigned long action, void *data)
|
|
+{
|
|
+ struct wireguard_device *wg = container_of(nb, struct wireguard_device, clear_peers_on_suspend);
|
|
+ if (action == PM_HIBERNATION_PREPARE || action == PM_SUSPEND_PREPARE) {
|
|
+ peer_for_each(wg, clear_noise_peer, NULL);
|
|
+ rcu_barrier();
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int stop_peer(struct wireguard_peer *peer, void *data)
|
|
+{
|
|
+ timers_uninit_peer(peer);
|
|
+ clear_noise_peer(peer, data);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stop(struct net_device *dev)
|
|
+{
|
|
+ struct wireguard_device *wg = netdev_priv(dev);
|
|
+ peer_for_each(wg, stop_peer, NULL);
|
|
+ skb_queue_purge(&wg->incoming_handshakes);
|
|
+ socket_uninit(wg);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void skb_unsendable(struct sk_buff *skb, struct net_device *dev)
|
|
+{
|
|
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
|
|
+ /* This conntrack stuff is because the rate limiting needs to be applied
|
|
+ * to the original src IP, so we have to restore saddr in the IP header.
|
|
+ * It's not needed if conntracking isn't in the kernel, because in that
|
|
+ * case the saddr wouldn't be NAT-transformed anyway. */
|
|
+ enum ip_conntrack_info ctinfo;
|
|
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
|
|
+#endif
|
|
+ ++dev->stats.tx_errors;
|
|
+
|
|
+ if (skb->len >= sizeof(struct iphdr) && ip_hdr(skb)->version == 4) {
|
|
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
|
|
+ if (ct)
|
|
+ ip_hdr(skb)->saddr = ct->tuplehash[0].tuple.src.u3.ip;
|
|
+#endif
|
|
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
|
|
+ } else if (skb->len >= sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6) {
|
|
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
|
|
+ if (ct)
|
|
+ ipv6_hdr(skb)->saddr = ct->tuplehash[0].tuple.src.u3.in6;
|
|
+#endif
|
|
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
|
|
+ }
|
|
+ kfree_skb(skb);
|
|
+}
|
|
+
|
|
+static netdev_tx_t xmit(struct sk_buff *skb, struct net_device *dev)
|
|
+{
|
|
+ struct wireguard_device *wg = netdev_priv(dev);
|
|
+ struct wireguard_peer *peer;
|
|
+ int ret;
|
|
+
|
|
+ if (unlikely(dev_recursion_level() > 4)) {
|
|
+ ret = -ELOOP;
|
|
+ net_dbg_ratelimited("Routing loop detected\n");
|
|
+ skb_unsendable(skb, dev);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ peer = routing_table_lookup_dst(&wg->peer_routing_table, skb);
|
|
+ if (unlikely(!peer)) {
|
|
+ ret = -ENOKEY;
|
|
+ net_dbg_skb_ratelimited("No peer is configured for %pISc\n", skb);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ read_lock_bh(&peer->endpoint_lock);
|
|
+ ret = peer->endpoint.addr.sa_family != AF_INET && peer->endpoint.addr.sa_family != AF_INET6;
|
|
+ read_unlock_bh(&peer->endpoint_lock);
|
|
+ if (unlikely(ret)) {
|
|
+ ret = -EHOSTUNREACH;
|
|
+ net_dbg_ratelimited("No valid endpoint has been configured or discovered for peer %Lu\n", peer->internal_id);
|
|
+ goto err_peer;
|
|
+ }
|
|
+
|
|
+ /* If the queue is getting too big, we start removing the oldest packets until it's small again.
|
|
+ * We do this before adding the new packet, so we don't remove GSO segments that are in excess. */
|
|
+ while (skb_queue_len(&peer->tx_packet_queue) > MAX_QUEUED_OUTGOING_PACKETS)
|
|
+ dev_kfree_skb(skb_dequeue(&peer->tx_packet_queue));
|
|
+
|
|
+ if (!skb_is_gso(skb))
|
|
+ skb->next = NULL;
|
|
+ else {
|
|
+ struct sk_buff *segs = skb_gso_segment(skb, 0);
|
|
+ if (unlikely(IS_ERR(segs))) {
|
|
+ ret = PTR_ERR(segs);
|
|
+ goto err_peer;
|
|
+ }
|
|
+ dev_kfree_skb(skb);
|
|
+ skb = segs;
|
|
+ }
|
|
+ while (skb) {
|
|
+ struct sk_buff *next = skb->next;
|
|
+ skb->next = skb->prev = NULL;
|
|
+
|
|
+ skb = skb_share_check(skb, GFP_ATOMIC);
|
|
+ if (unlikely(!skb))
|
|
+ continue;
|
|
+
|
|
+ /* We only need to keep the original dst around for icmp,
|
|
+ * so at this point we're in a position to drop it. */
|
|
+ skb_dst_drop(skb);
|
|
+
|
|
+ skb_queue_tail(&peer->tx_packet_queue, skb);
|
|
+ skb = next;
|
|
+ }
|
|
+
|
|
+ packet_send_queue(peer);
|
|
+ peer_put(peer);
|
|
+ return NETDEV_TX_OK;
|
|
+
|
|
+err_peer:
|
|
+ peer_put(peer);
|
|
+err:
|
|
+ skb_unsendable(skb, dev);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+
|
|
+static int ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|
+{
|
|
+ struct wireguard_device *wg = netdev_priv(dev);
|
|
+
|
|
+ if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN))
|
|
+ return -EPERM;
|
|
+
|
|
+ switch (cmd) {
|
|
+ case WG_GET_DEVICE:
|
|
+ return config_get_device(wg, ifr->ifr_ifru.ifru_data);
|
|
+ case WG_SET_DEVICE:
|
|
+ return config_set_device(wg, ifr->ifr_ifru.ifru_data);
|
|
+ }
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+static const struct net_device_ops netdev_ops = {
|
|
+ .ndo_open = open,
|
|
+ .ndo_stop = stop,
|
|
+ .ndo_start_xmit = xmit,
|
|
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
|
|
+ .ndo_do_ioctl = ioctl
|
|
+};
|
|
+
|
|
+static void destruct(struct net_device *dev)
|
|
+{
|
|
+ struct wireguard_device *wg = netdev_priv(dev);
|
|
+
|
|
+ mutex_lock(&wg->device_update_lock);
|
|
+ peer_remove_all(wg);
|
|
+ wg->incoming_port = 0;
|
|
+ destroy_workqueue(wg->workqueue);
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ padata_free(wg->parallel_send);
|
|
+ padata_free(wg->parallel_receive);
|
|
+ destroy_workqueue(wg->parallelqueue);
|
|
+#endif
|
|
+ routing_table_free(&wg->peer_routing_table);
|
|
+ memzero_explicit(&wg->static_identity, sizeof(struct noise_static_identity));
|
|
+ skb_queue_purge(&wg->incoming_handshakes);
|
|
+ socket_uninit(wg);
|
|
+ cookie_checker_uninit(&wg->cookie_checker);
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
+ unregister_pm_notifier(&wg->clear_peers_on_suspend);
|
|
+#endif
|
|
+ mutex_unlock(&wg->device_update_lock);
|
|
+ free_percpu(dev->tstats);
|
|
+
|
|
+ put_net(wg->creating_net);
|
|
+
|
|
+ pr_debug("Device %s has been deleted\n", dev->name);
|
|
+ free_netdev(dev);
|
|
+}
|
|
+
|
|
+static void setup(struct net_device *dev)
|
|
+{
|
|
+ struct wireguard_device *wg = netdev_priv(dev);
|
|
+ enum { WG_NETDEV_FEATURES = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA };
|
|
+
|
|
+ dev->netdev_ops = &netdev_ops;
|
|
+ dev->destructor = destruct;
|
|
+ dev->hard_header_len = 0;
|
|
+ dev->addr_len = 0;
|
|
+ dev->needed_headroom = DATA_PACKET_HEAD_ROOM;
|
|
+ dev->needed_tailroom = noise_encrypted_len(MESSAGE_PADDING_MULTIPLE);
|
|
+ dev->type = ARPHRD_NONE;
|
|
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
|
+ dev->flags |= IFF_NO_QUEUE;
|
|
+#else
|
|
+ dev->tx_queue_len = 0;
|
|
+#endif
|
|
+ dev->features |= NETIF_F_LLTX;
|
|
+ dev->features |= WG_NETDEV_FEATURES;
|
|
+ dev->hw_features |= WG_NETDEV_FEATURES;
|
|
+ dev->hw_enc_features |= WG_NETDEV_FEATURES;
|
|
+ dev->mtu = ETH_DATA_LEN - MESSAGE_MINIMUM_LENGTH - sizeof(struct udphdr) - max(sizeof(struct ipv6hdr), sizeof(struct iphdr));
|
|
+
|
|
+ /* We need to keep the dst around in case of icmp replies. */
|
|
+ netif_keep_dst(dev);
|
|
+
|
|
+ memset(wg, 0, sizeof(struct wireguard_device));
|
|
+}
|
|
+
|
|
+static int newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[])
|
|
+{
|
|
+ int ret = -ENOMEM;
|
|
+ struct wireguard_device *wg = netdev_priv(dev);
|
|
+
|
|
+ wg->creating_net = get_net(src_net);
|
|
+ init_rwsem(&wg->static_identity.lock);
|
|
+ mutex_init(&wg->socket_update_lock);
|
|
+ mutex_init(&wg->device_update_lock);
|
|
+ skb_queue_head_init(&wg->incoming_handshakes);
|
|
+ INIT_WORK(&wg->incoming_handshakes_work, packet_process_queued_handshake_packets);
|
|
+ pubkey_hashtable_init(&wg->peer_hashtable);
|
|
+ index_hashtable_init(&wg->index_hashtable);
|
|
+ routing_table_init(&wg->peer_routing_table);
|
|
+ INIT_LIST_HEAD(&wg->peer_list);
|
|
+
|
|
+ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
|
+ if (!dev->tstats)
|
|
+ goto error_1;
|
|
+
|
|
+ wg->workqueue = alloc_workqueue("wg-%s", WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name);
|
|
+ if (!wg->workqueue)
|
|
+ goto error_2;
|
|
+
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ wg->parallelqueue = alloc_workqueue("wg-crypt-%s", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1, dev->name);
|
|
+ if (!wg->parallelqueue)
|
|
+ goto error_3;
|
|
+
|
|
+ wg->parallel_send = padata_alloc_possible(wg->parallelqueue);
|
|
+ if (!wg->parallel_send)
|
|
+ goto error_4;
|
|
+ padata_start(wg->parallel_send);
|
|
+
|
|
+ wg->parallel_receive = padata_alloc_possible(wg->parallelqueue);
|
|
+ if (!wg->parallel_receive)
|
|
+ goto error_5;
|
|
+ padata_start(wg->parallel_receive);
|
|
+#endif
|
|
+
|
|
+ ret = cookie_checker_init(&wg->cookie_checker, wg);
|
|
+ if (ret < 0)
|
|
+ goto error_6;
|
|
+
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
+ wg->clear_peers_on_suspend.notifier_call = suspending_clear_noise_peers;
|
|
+ ret = register_pm_notifier(&wg->clear_peers_on_suspend);
|
|
+ if (ret < 0)
|
|
+ goto error_7;
|
|
+#endif
|
|
+
|
|
+ ret = register_netdevice(dev);
|
|
+ if (ret < 0)
|
|
+ goto error_8;
|
|
+
|
|
+ pr_debug("Device %s has been created\n", dev->name);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error_8:
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
+ unregister_pm_notifier(&wg->clear_peers_on_suspend);
|
|
+error_7:
|
|
+#endif
|
|
+ cookie_checker_uninit(&wg->cookie_checker);
|
|
+error_6:
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ padata_free(wg->parallel_receive);
|
|
+error_5:
|
|
+ padata_free(wg->parallel_send);
|
|
+error_4:
|
|
+ destroy_workqueue(wg->parallelqueue);
|
|
+error_3:
|
|
+#endif
|
|
+ destroy_workqueue(wg->workqueue);
|
|
+error_2:
|
|
+ free_percpu(dev->tstats);
|
|
+error_1:
|
|
+ put_net(src_net);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static struct rtnl_link_ops link_ops __read_mostly = {
|
|
+ .kind = KBUILD_MODNAME,
|
|
+ .priv_size = sizeof(struct wireguard_device),
|
|
+ .setup = setup,
|
|
+ .newlink = newlink,
|
|
+};
|
|
+
|
|
+int device_init(void)
|
|
+{
|
|
+ return rtnl_link_register(&link_ops);
|
|
+}
|
|
+
|
|
+void device_uninit(void)
|
|
+{
|
|
+ rtnl_link_unregister(&link_ops);
|
|
+ rcu_barrier();
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/hashtables.c
|
|
@@ -0,0 +1,136 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "hashtables.h"
|
|
+#include "peer.h"
|
|
+#include "noise.h"
|
|
+
|
|
+static inline struct hlist_head *pubkey_bucket(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN])
|
|
+{
|
|
+ /* siphash gives us a secure 64bit number based on a random key. Since the bits are
|
|
+ * uniformly distributed, we can then mask off to get the bits we need. */
|
|
+ return &table->hashtable[siphash(pubkey, NOISE_PUBLIC_KEY_LEN, &table->key) & (HASH_SIZE(table->hashtable) - 1)];
|
|
+}
|
|
+
|
|
+void pubkey_hashtable_init(struct pubkey_hashtable *table)
|
|
+{
|
|
+ get_random_bytes(&table->key, sizeof(table->key));
|
|
+ hash_init(table->hashtable);
|
|
+ mutex_init(&table->lock);
|
|
+}
|
|
+
|
|
+void pubkey_hashtable_add(struct pubkey_hashtable *table, struct wireguard_peer *peer)
|
|
+{
|
|
+ mutex_lock(&table->lock);
|
|
+ hlist_add_head_rcu(&peer->pubkey_hash, pubkey_bucket(table, peer->handshake.remote_static));
|
|
+ mutex_unlock(&table->lock);
|
|
+}
|
|
+
|
|
+void pubkey_hashtable_remove(struct pubkey_hashtable *table, struct wireguard_peer *peer)
|
|
+{
|
|
+ mutex_lock(&table->lock);
|
|
+ hlist_del_init_rcu(&peer->pubkey_hash);
|
|
+ mutex_unlock(&table->lock);
|
|
+}
|
|
+
|
|
+/* Returns a strong reference to a peer */
|
|
+struct wireguard_peer *pubkey_hashtable_lookup(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN])
|
|
+{
|
|
+ struct wireguard_peer *iter_peer, *peer = NULL;
|
|
+ rcu_read_lock();
|
|
+ hlist_for_each_entry_rcu(iter_peer, pubkey_bucket(table, pubkey), pubkey_hash) {
|
|
+ if (!memcmp(pubkey, iter_peer->handshake.remote_static, NOISE_PUBLIC_KEY_LEN)) {
|
|
+ peer = iter_peer;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ peer = peer_get(peer);
|
|
+ rcu_read_unlock();
|
|
+ return peer;
|
|
+}
|
|
+
|
|
+static inline struct hlist_head *index_bucket(struct index_hashtable *table, const __le32 index)
|
|
+{
|
|
+ /* Since the indices are random and thus all bits are uniformly distributed,
|
|
+ * we can find its bucket simply by masking. */
|
|
+ return &table->hashtable[(__force u32)index & (HASH_SIZE(table->hashtable) - 1)];
|
|
+}
|
|
+
|
|
+void index_hashtable_init(struct index_hashtable *table)
|
|
+{
|
|
+ get_random_bytes(&table->key, sizeof(table->key));
|
|
+ hash_init(table->hashtable);
|
|
+ spin_lock_init(&table->lock);
|
|
+}
|
|
+
|
|
+__le32 index_hashtable_insert(struct index_hashtable *table, struct index_hashtable_entry *entry)
|
|
+{
|
|
+ struct index_hashtable_entry *existing_entry;
|
|
+ u32 counter = get_random_int();
|
|
+
|
|
+ spin_lock(&table->lock);
|
|
+ hlist_del_init_rcu(&entry->index_hash);
|
|
+ spin_unlock(&table->lock);
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+search_unused_slot:
|
|
+ /* First we try to find an unused slot, randomly, while unlocked. */
|
|
+ entry->index = (__force __le32)siphash_2u32(get_random_int(), counter++, &table->key);
|
|
+ hlist_for_each_entry_rcu(existing_entry, index_bucket(table, entry->index), index_hash) {
|
|
+ if (existing_entry->index == entry->index)
|
|
+ goto search_unused_slot; /* If it's already in use, we continue searching. */
|
|
+ }
|
|
+
|
|
+ /* Once we've found an unused slot, we lock it, and then double-check
|
|
+ * that nobody else stole it from us. */
|
|
+ spin_lock(&table->lock);
|
|
+ hlist_for_each_entry_rcu(existing_entry, index_bucket(table, entry->index), index_hash) {
|
|
+ if (existing_entry->index == entry->index) {
|
|
+ spin_unlock(&table->lock);
|
|
+ goto search_unused_slot; /* If it was stolen, we start over. */
|
|
+ }
|
|
+ }
|
|
+ /* Otherwise, we know we have it exclusively (since we're locked), so we insert. */
|
|
+ hlist_add_head_rcu(&entry->index_hash, index_bucket(table, entry->index));
|
|
+ spin_unlock(&table->lock);
|
|
+
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ return entry->index;
|
|
+}
|
|
+
|
|
+void index_hashtable_replace(struct index_hashtable *table, struct index_hashtable_entry *old, struct index_hashtable_entry *new)
|
|
+{
|
|
+ spin_lock(&table->lock);
|
|
+ new->index = old->index;
|
|
+ hlist_replace_rcu(&old->index_hash, &new->index_hash);
|
|
+ INIT_HLIST_NODE(&old->index_hash);
|
|
+ spin_unlock(&table->lock);
|
|
+}
|
|
+
|
|
+void index_hashtable_remove(struct index_hashtable *table, struct index_hashtable_entry *entry)
|
|
+{
|
|
+ spin_lock(&table->lock);
|
|
+ hlist_del_init_rcu(&entry->index_hash);
|
|
+ spin_unlock(&table->lock);
|
|
+}
|
|
+
|
|
+/* Returns a strong reference to a entry->peer */
|
|
+struct index_hashtable_entry *index_hashtable_lookup(struct index_hashtable *table, const enum index_hashtable_type type_mask, const __le32 index)
|
|
+{
|
|
+ struct index_hashtable_entry *iter_entry, *entry = NULL;
|
|
+ rcu_read_lock();
|
|
+ hlist_for_each_entry_rcu(iter_entry, index_bucket(table, index), index_hash) {
|
|
+ if (iter_entry->index == index && (iter_entry->type & type_mask)) {
|
|
+ entry = iter_entry;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (likely(entry)) {
|
|
+ entry->peer = peer_get(entry->peer);
|
|
+ if (unlikely(!entry->peer))
|
|
+ entry = NULL;
|
|
+ }
|
|
+ rcu_read_unlock();
|
|
+ return entry;
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/main.c
|
|
@@ -0,0 +1,70 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "version.h"
|
|
+#include "device.h"
|
|
+#include "noise.h"
|
|
+#include "packets.h"
|
|
+#include "crypto/chacha20poly1305.h"
|
|
+#include "crypto/blake2s.h"
|
|
+#include "crypto/curve25519.h"
|
|
+
|
|
+#include <linux/version.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <net/rtnetlink.h>
|
|
+
|
|
+static int __init mod_init(void)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ if (!routing_table_selftest() || !packet_counter_selftest() || !curve25519_selftest() || !chacha20poly1305_selftest() || !blake2s_selftest())
|
|
+ return -ENOTRECOVERABLE;
|
|
+#endif
|
|
+ chacha20poly1305_init();
|
|
+ noise_init();
|
|
+
|
|
+ ret = ratelimiter_module_init();
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ ret = packet_init_data_caches();
|
|
+ if (ret < 0)
|
|
+ goto err_packet;
|
|
+#endif
|
|
+
|
|
+ ret = device_init();
|
|
+ if (ret < 0)
|
|
+ goto err_device;
|
|
+
|
|
+ pr_info("WireGuard " WIREGUARD_VERSION " loaded. See www.wireguard.io for information.\n");
|
|
+ pr_info("Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.\n");
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_device:
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ packet_deinit_data_caches();
|
|
+err_packet:
|
|
+#endif
|
|
+ ratelimiter_module_deinit();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void __exit mod_exit(void)
|
|
+{
|
|
+ device_uninit();
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ packet_deinit_data_caches();
|
|
+#endif
|
|
+ ratelimiter_module_deinit();
|
|
+ pr_debug("WireGuard has been unloaded\n");
|
|
+}
|
|
+
|
|
+module_init(mod_init);
|
|
+module_exit(mod_exit);
|
|
+MODULE_LICENSE("GPL v2");
|
|
+MODULE_DESCRIPTION("Fast, secure, and modern VPN tunnel");
|
|
+MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
|
|
+MODULE_ALIAS_RTNL_LINK(KBUILD_MODNAME);
|
|
--- /dev/null
|
|
+++ b/net/wireguard/noise.c
|
|
@@ -0,0 +1,593 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "noise.h"
|
|
+#include "device.h"
|
|
+#include "peer.h"
|
|
+#include "messages.h"
|
|
+#include "packets.h"
|
|
+#include "hashtables.h"
|
|
+
|
|
+#include <linux/rcupdate.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/bitmap.h>
|
|
+#include <linux/scatterlist.h>
|
|
+#include <linux/highmem.h>
|
|
+#include <crypto/algapi.h>
|
|
+
|
|
+/* This implements Noise_IK:
|
|
+ *
|
|
+ * <- s
|
|
+ * ******
|
|
+ * -> e, es, s, ss, t
|
|
+ * <- e, ee, se
|
|
+ */
|
|
+
|
|
+static const u8 handshake_name[33] = "Noise_IK_25519_ChaChaPoly_BLAKE2s";
|
|
+static const u8 handshake_psk_name[36] = "NoisePSK_IK_25519_ChaChaPoly_BLAKE2s";
|
|
+static u8 handshake_name_hash[NOISE_HASH_LEN] __read_mostly;
|
|
+static u8 handshake_psk_name_hash[NOISE_HASH_LEN] __read_mostly;
|
|
+static const u8 identifier_name[34] = "WireGuard v0 zx2c4 Jason@zx2c4.com";
|
|
+static atomic64_t keypair_counter = ATOMIC64_INIT(0);
|
|
+
|
|
+void noise_init(void)
|
|
+{
|
|
+ blake2s(handshake_name_hash, handshake_name, NULL, NOISE_HASH_LEN, sizeof(handshake_name), 0);
|
|
+ blake2s(handshake_psk_name_hash, handshake_psk_name, NULL, NOISE_HASH_LEN, sizeof(handshake_psk_name), 0);
|
|
+}
|
|
+
|
|
+void noise_handshake_init(struct noise_handshake *handshake, struct noise_static_identity *static_identity, const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], struct wireguard_peer *peer)
|
|
+{
|
|
+ memset(handshake, 0, sizeof(struct noise_handshake));
|
|
+ init_rwsem(&handshake->lock);
|
|
+ handshake->entry.type = INDEX_HASHTABLE_HANDSHAKE;
|
|
+ handshake->entry.peer = peer;
|
|
+ memcpy(handshake->remote_static, peer_public_key, NOISE_PUBLIC_KEY_LEN);
|
|
+ handshake->static_identity = static_identity;
|
|
+ handshake->state = HANDSHAKE_ZEROED;
|
|
+}
|
|
+
|
|
+void noise_handshake_clear(struct noise_handshake *handshake)
|
|
+{
|
|
+ index_hashtable_remove(&handshake->entry.peer->device->index_hashtable, &handshake->entry);
|
|
+ down_write(&handshake->lock);
|
|
+ memset(&handshake->ephemeral_public, 0, NOISE_PUBLIC_KEY_LEN);
|
|
+ memset(&handshake->ephemeral_private, 0, NOISE_PUBLIC_KEY_LEN);
|
|
+ memset(&handshake->remote_ephemeral, 0, NOISE_PUBLIC_KEY_LEN);
|
|
+ memset(&handshake->hash, 0, NOISE_HASH_LEN);
|
|
+ memset(&handshake->chaining_key, 0, NOISE_HASH_LEN);
|
|
+ memset(&handshake->key, 0, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ handshake->remote_index = 0;
|
|
+ handshake->state = HANDSHAKE_ZEROED;
|
|
+ up_write(&handshake->lock);
|
|
+ index_hashtable_remove(&handshake->entry.peer->device->index_hashtable, &handshake->entry);
|
|
+}
|
|
+
|
|
+static struct noise_keypair *keypair_create(struct wireguard_peer *peer)
|
|
+{
|
|
+ struct noise_keypair *keypair = kzalloc(sizeof(struct noise_keypair), GFP_KERNEL);
|
|
+ if (unlikely(!keypair))
|
|
+ return NULL;
|
|
+ keypair->internal_id = atomic64_inc_return(&keypair_counter);
|
|
+ keypair->entry.type = INDEX_HASHTABLE_KEYPAIR;
|
|
+ keypair->entry.peer = peer;
|
|
+ kref_init(&keypair->refcount);
|
|
+ return keypair;
|
|
+}
|
|
+
|
|
+static void keypair_free_rcu(struct rcu_head *rcu)
|
|
+{
|
|
+ struct noise_keypair *keypair = container_of(rcu, struct noise_keypair, rcu);
|
|
+ net_dbg_ratelimited("Keypair %Lu destroyed for peer %Lu\n", keypair->internal_id, keypair->entry.peer->internal_id);
|
|
+ kzfree(keypair);
|
|
+}
|
|
+
|
|
+static void keypair_free_kref(struct kref *kref)
|
|
+{
|
|
+ struct noise_keypair *keypair = container_of(kref, struct noise_keypair, refcount);
|
|
+ index_hashtable_remove(&keypair->entry.peer->device->index_hashtable, &keypair->entry);
|
|
+ call_rcu(&keypair->rcu, keypair_free_rcu);
|
|
+}
|
|
+
|
|
+void noise_keypair_put(struct noise_keypair *keypair)
|
|
+{
|
|
+ if (unlikely(!keypair))
|
|
+ return;
|
|
+ kref_put(&keypair->refcount, keypair_free_kref);
|
|
+}
|
|
+
|
|
+struct noise_keypair *noise_keypair_get(struct noise_keypair *keypair)
|
|
+{
|
|
+ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "Calling noise_keypair_get without holding the RCU read lock.");
|
|
+ if (unlikely(!keypair || !kref_get_unless_zero(&keypair->refcount)))
|
|
+ return NULL;
|
|
+ return keypair;
|
|
+}
|
|
+
|
|
+void noise_keypairs_clear(struct noise_keypairs *keypairs)
|
|
+{
|
|
+ struct noise_keypair *old;
|
|
+ mutex_lock(&keypairs->keypair_update_lock);
|
|
+ old = rcu_dereference_protected(keypairs->previous_keypair, lockdep_is_held(&keypairs->keypair_update_lock));
|
|
+ rcu_assign_pointer(keypairs->previous_keypair, NULL);
|
|
+ noise_keypair_put(old);
|
|
+ old = rcu_dereference_protected(keypairs->next_keypair, lockdep_is_held(&keypairs->keypair_update_lock));
|
|
+ rcu_assign_pointer(keypairs->next_keypair, NULL);
|
|
+ noise_keypair_put(old);
|
|
+ old = rcu_dereference_protected(keypairs->current_keypair, lockdep_is_held(&keypairs->keypair_update_lock));
|
|
+ rcu_assign_pointer(keypairs->current_keypair, NULL);
|
|
+ noise_keypair_put(old);
|
|
+ mutex_unlock(&keypairs->keypair_update_lock);
|
|
+}
|
|
+
|
|
+static void add_new_keypair(struct noise_keypairs *keypairs, struct noise_keypair *new_keypair)
|
|
+{
|
|
+ struct noise_keypair *previous_keypair, *next_keypair, *current_keypair;
|
|
+
|
|
+ mutex_lock(&keypairs->keypair_update_lock);
|
|
+ previous_keypair = rcu_dereference_protected(keypairs->previous_keypair, lockdep_is_held(&keypairs->keypair_update_lock));
|
|
+ next_keypair = rcu_dereference_protected(keypairs->next_keypair, lockdep_is_held(&keypairs->keypair_update_lock));
|
|
+ current_keypair = rcu_dereference_protected(keypairs->current_keypair, lockdep_is_held(&keypairs->keypair_update_lock));
|
|
+ if (new_keypair->i_am_the_initiator) {
|
|
+ /* If we're the initiator, it means we've sent a handshake, and received
|
|
+ * a confirmation response, which means this new keypair can now be used. */
|
|
+ if (next_keypair) {
|
|
+ /* If there already was a next keypair pending, we demote it to be
|
|
+ * the previous keypair, and free the existing current.
|
|
+ * TODO: note that this means KCI can result in this transition. It
|
|
+ * would perhaps be more sound to always just get rid of the unused
|
|
+ * next keypair instead of putting it in the previous slot, but this
|
|
+ * might be a bit less robust. Something to think about and decide on. */
|
|
+ rcu_assign_pointer(keypairs->next_keypair, NULL);
|
|
+ rcu_assign_pointer(keypairs->previous_keypair, next_keypair);
|
|
+ noise_keypair_put(current_keypair);
|
|
+ } else /* If there wasn't an existing next keypair, we replace the
|
|
+ * previous with the current one. */
|
|
+ rcu_assign_pointer(keypairs->previous_keypair, current_keypair);
|
|
+ /* At this point we can get rid of the old previous keypair, and set up
|
|
+ * the new keypair. */
|
|
+ noise_keypair_put(previous_keypair);
|
|
+ rcu_assign_pointer(keypairs->current_keypair, new_keypair);
|
|
+ } else {
|
|
+ /* If we're the responder, it means we can't use the new keypair until
|
|
+ * we receive confirmation via the first data packet, so we get rid of
|
|
+ * the existing previous one, the possibly existing next one, and slide
|
|
+ * in the new next one. */
|
|
+ rcu_assign_pointer(keypairs->next_keypair, new_keypair);
|
|
+ noise_keypair_put(next_keypair);
|
|
+ rcu_assign_pointer(keypairs->previous_keypair, NULL);
|
|
+ noise_keypair_put(previous_keypair);
|
|
+ }
|
|
+ mutex_unlock(&keypairs->keypair_update_lock);
|
|
+}
|
|
+
|
|
+bool noise_received_with_keypair(struct noise_keypairs *keypairs, struct noise_keypair *received_keypair)
|
|
+{
|
|
+ bool ret = false;
|
|
+ struct noise_keypair *old_keypair;
|
|
+
|
|
+ /* TODO: probably this needs the actual mutex, but we're in atomic context,
|
|
+ * so we can't take it here. Instead we just rely on RCU for the lookups. */
|
|
+ rcu_read_lock();
|
|
+ if (unlikely(received_keypair == rcu_dereference(keypairs->next_keypair))) {
|
|
+ ret = true;
|
|
+ /* When we've finally received the confirmation, we slide the next
|
|
+ * into the current, the current into the previous, and get rid of
|
|
+ * the old previous. */
|
|
+ old_keypair = rcu_dereference(keypairs->previous_keypair);
|
|
+ rcu_assign_pointer(keypairs->previous_keypair, rcu_dereference(keypairs->current_keypair));
|
|
+ noise_keypair_put(old_keypair);
|
|
+ rcu_assign_pointer(keypairs->current_keypair, received_keypair);
|
|
+ rcu_assign_pointer(keypairs->next_keypair, NULL);
|
|
+ }
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void noise_set_static_identity_private_key(struct noise_static_identity *static_identity, const u8 private_key[NOISE_PUBLIC_KEY_LEN])
|
|
+{
|
|
+ down_write(&static_identity->lock);
|
|
+ if (private_key) {
|
|
+ memcpy(static_identity->static_private, private_key, NOISE_PUBLIC_KEY_LEN);
|
|
+ curve25519_generate_public(static_identity->static_public, private_key);
|
|
+ static_identity->has_identity = true;
|
|
+ } else {
|
|
+ memset(static_identity->static_private, 0, NOISE_PUBLIC_KEY_LEN);
|
|
+ memset(static_identity->static_public, 0, NOISE_PUBLIC_KEY_LEN);
|
|
+ static_identity->has_identity = false;
|
|
+ }
|
|
+ up_write(&static_identity->lock);
|
|
+}
|
|
+
|
|
+void noise_set_static_identity_preshared_key(struct noise_static_identity *static_identity, const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN])
|
|
+{
|
|
+ down_write(&static_identity->lock);
|
|
+ if (preshared_key) {
|
|
+ memcpy(static_identity->preshared_key, preshared_key, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ static_identity->has_psk = true;
|
|
+ } else {
|
|
+ memset(static_identity->preshared_key, 0, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ static_identity->has_psk = false;
|
|
+ }
|
|
+ up_write(&static_identity->lock);
|
|
+}
|
|
+
|
|
+/* This is Hugo Krawczyk's HKDF:
|
|
+ * - https://eprint.iacr.org/2010/264.pdf
|
|
+ * - https://tools.ietf.org/html/rfc5869
|
|
+ */
|
|
+static void kdf(u8 *first_dst, u8 *second_dst, const u8 *data,
|
|
+ size_t first_len, size_t second_len, size_t data_len,
|
|
+ const u8 chaining_key[NOISE_HASH_LEN])
|
|
+{
|
|
+ u8 secret[BLAKE2S_OUTBYTES];
|
|
+ u8 output[BLAKE2S_OUTBYTES + 1];
|
|
+ BUG_ON(first_len > BLAKE2S_OUTBYTES || second_len > BLAKE2S_OUTBYTES);
|
|
+
|
|
+ /* Extract entropy from data into secret */
|
|
+ blake2s_hmac(secret, data, chaining_key, BLAKE2S_OUTBYTES, data_len, NOISE_HASH_LEN);
|
|
+
|
|
+ /* Expand first key: key = secret, data = 0x1 */
|
|
+ output[0] = 1;
|
|
+ blake2s_hmac(output, output, secret, BLAKE2S_OUTBYTES, 1, BLAKE2S_OUTBYTES);
|
|
+ memcpy(first_dst, output, first_len);
|
|
+
|
|
+ /* Expand second key: key = secret, data = first-key || 0x2 */
|
|
+ output[BLAKE2S_OUTBYTES] = 2;
|
|
+ blake2s_hmac(output, output, secret, BLAKE2S_OUTBYTES, BLAKE2S_OUTBYTES + 1, BLAKE2S_OUTBYTES);
|
|
+ memcpy(second_dst, output, second_len);
|
|
+
|
|
+ /* Clear sensitive data from stack */
|
|
+ memzero_explicit(secret, BLAKE2S_OUTBYTES);
|
|
+ memzero_explicit(output, BLAKE2S_OUTBYTES + 1);
|
|
+}
|
|
+
|
|
+static void symmetric_key_init(struct noise_symmetric_key *key)
|
|
+{
|
|
+ spin_lock_init(&key->counter.receive.lock);
|
|
+ atomic64_set(&key->counter.counter, 0);
|
|
+ memset(key->counter.receive.backtrack, 0, sizeof(key->counter.receive.backtrack));
|
|
+ key->birthdate = get_jiffies_64();
|
|
+ key->is_valid = true;
|
|
+}
|
|
+
|
|
+static void derive_keys(struct noise_symmetric_key *first_dst, struct noise_symmetric_key *second_dst, const u8 chaining_key[NOISE_HASH_LEN])
|
|
+{
|
|
+ kdf(first_dst->key, second_dst->key, NULL, NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, chaining_key);
|
|
+ symmetric_key_init(first_dst);
|
|
+ symmetric_key_init(second_dst);
|
|
+}
|
|
+
|
|
+static void mix_key(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN], const u8 *src, size_t src_len)
|
|
+{
|
|
+ kdf(chaining_key, key, src, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, src_len, chaining_key);
|
|
+}
|
|
+
|
|
+static void mix_dh(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN],
|
|
+ const u8 private[NOISE_PUBLIC_KEY_LEN], const u8 public[NOISE_PUBLIC_KEY_LEN])
|
|
+{
|
|
+ u8 dh_calculation[NOISE_PUBLIC_KEY_LEN];
|
|
+ curve25519(dh_calculation, private, public);
|
|
+ mix_key(key, chaining_key, dh_calculation, NOISE_PUBLIC_KEY_LEN);
|
|
+ memzero_explicit(dh_calculation, NOISE_PUBLIC_KEY_LEN);
|
|
+}
|
|
+
|
|
+static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len)
|
|
+{
|
|
+ struct blake2s_state blake;
|
|
+ blake2s_init(&blake, NOISE_HASH_LEN);
|
|
+ blake2s_update(&blake, hash, NOISE_HASH_LEN);
|
|
+ blake2s_update(&blake, src, src_len);
|
|
+ blake2s_final(&blake, hash, NOISE_HASH_LEN);
|
|
+}
|
|
+
|
|
+static void handshake_init(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN], u8 hash[NOISE_HASH_LEN],
|
|
+ const u8 remote_static[NOISE_PUBLIC_KEY_LEN], const u8 psk[NOISE_SYMMETRIC_KEY_LEN])
|
|
+{
|
|
+ memset(key, 0, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ memcpy(hash, psk ? handshake_psk_name_hash : handshake_name_hash, NOISE_HASH_LEN);
|
|
+ mix_hash(hash, identifier_name, sizeof(identifier_name));
|
|
+ if (psk) {
|
|
+ u8 temp_hash[NOISE_HASH_LEN];
|
|
+ kdf(chaining_key, temp_hash, psk, NOISE_HASH_LEN, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, handshake_psk_name_hash);
|
|
+ mix_hash(hash, temp_hash, NOISE_HASH_LEN);
|
|
+ memzero_explicit(temp_hash, NOISE_HASH_LEN);
|
|
+ } else
|
|
+ memcpy(chaining_key, handshake_name_hash, NOISE_HASH_LEN);
|
|
+ mix_hash(hash, remote_static, NOISE_PUBLIC_KEY_LEN);
|
|
+}
|
|
+
|
|
+static bool handshake_encrypt(u8 *dst_ciphertext, const u8 *src_plaintext, size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 hash[NOISE_HASH_LEN])
|
|
+{
|
|
+ if (!chacha20poly1305_encrypt(dst_ciphertext, src_plaintext, src_len, hash, NOISE_HASH_LEN, 0 /* Always zero for Noise_IK */, key))
|
|
+ return false;
|
|
+ mix_hash(hash, dst_ciphertext, noise_encrypted_len(src_len));
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static bool handshake_decrypt(u8 *dst_plaintext, const u8 *src_ciphertext, size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 hash[NOISE_HASH_LEN])
|
|
+{
|
|
+ if (!chacha20poly1305_decrypt(dst_plaintext, src_ciphertext, src_len, hash, NOISE_HASH_LEN, 0 /* Always zero for Noise_IK */, key))
|
|
+ return false;
|
|
+ mix_hash(hash, src_ciphertext, src_len);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static void handshake_nocrypt(u8 *dst, const u8 *src, size_t src_len, u8 hash[NOISE_HASH_LEN])
|
|
+{
|
|
+ memcpy(dst, src, src_len);
|
|
+ mix_hash(hash, src, src_len);
|
|
+}
|
|
+
|
|
+static void tai64n_now(u8 output[NOISE_TIMESTAMP_LEN])
|
|
+{
|
|
+ struct timeval now;
|
|
+ do_gettimeofday(&now);
|
|
+ /* https://cr.yp.to/libtai/tai64.html */
|
|
+ *(__be64 *)output = cpu_to_be64(4611686018427387914ULL + now.tv_sec);
|
|
+ *(__be32 *)(output + sizeof(__be64)) = cpu_to_be32(1000 * now.tv_usec + 500);
|
|
+}
|
|
+
|
|
+bool noise_handshake_create_initiation(struct message_handshake_initiation *dst, struct noise_handshake *handshake)
|
|
+{
|
|
+ u8 timestamp[NOISE_TIMESTAMP_LEN];
|
|
+ bool ret = false;
|
|
+
|
|
+ down_read(&handshake->static_identity->lock);
|
|
+ down_write(&handshake->lock);
|
|
+
|
|
+ if (unlikely(!handshake->static_identity->has_identity))
|
|
+ goto out;
|
|
+
|
|
+ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION);
|
|
+
|
|
+ handshake_init(handshake->key, handshake->chaining_key, handshake->hash, handshake->remote_static,
|
|
+ handshake->static_identity->has_psk ? handshake->static_identity->preshared_key : NULL);
|
|
+
|
|
+ /* e */
|
|
+ curve25519_generate_secret(handshake->ephemeral_private);
|
|
+ curve25519_generate_public(handshake->ephemeral_public, handshake->ephemeral_private);
|
|
+ handshake_nocrypt(dst->unencrypted_ephemeral, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN, handshake->hash);
|
|
+ if (handshake->static_identity->has_psk)
|
|
+ mix_key(handshake->key, handshake->chaining_key, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN);
|
|
+
|
|
+ /* es */
|
|
+ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_static);
|
|
+
|
|
+ /* s */
|
|
+ if (!handshake_encrypt(dst->encrypted_static, handshake->static_identity->static_public, NOISE_PUBLIC_KEY_LEN, handshake->key, handshake->hash))
|
|
+ goto out;
|
|
+
|
|
+ /* ss */
|
|
+ mix_dh(handshake->key, handshake->chaining_key, handshake->static_identity->static_private, handshake->remote_static);
|
|
+
|
|
+ /* t */
|
|
+ tai64n_now(timestamp);
|
|
+ if (!handshake_encrypt(dst->encrypted_timestamp, timestamp, NOISE_TIMESTAMP_LEN, handshake->key, handshake->hash))
|
|
+ goto out;
|
|
+
|
|
+ dst->sender_index = index_hashtable_insert(&handshake->entry.peer->device->index_hashtable, &handshake->entry);
|
|
+
|
|
+ ret = true;
|
|
+ handshake->state = HANDSHAKE_CREATED_INITIATION;
|
|
+
|
|
+out:
|
|
+ up_write(&handshake->lock);
|
|
+ up_read(&handshake->static_identity->lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+struct wireguard_peer *noise_handshake_consume_initiation(struct message_handshake_initiation *src, struct wireguard_device *wg)
|
|
+{
|
|
+ bool replay_attack, flood_attack;
|
|
+ u8 s[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 e[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 t[NOISE_TIMESTAMP_LEN];
|
|
+ struct noise_handshake *handshake;
|
|
+ struct wireguard_peer *wg_peer = NULL;
|
|
+ u8 key[NOISE_SYMMETRIC_KEY_LEN];
|
|
+ u8 hash[NOISE_HASH_LEN];
|
|
+ u8 chaining_key[NOISE_HASH_LEN];
|
|
+
|
|
+ down_read(&wg->static_identity.lock);
|
|
+ if (unlikely(!wg->static_identity.has_identity))
|
|
+ goto out;
|
|
+
|
|
+ handshake_init(key, chaining_key, hash, wg->static_identity.static_public,
|
|
+ wg->static_identity.has_psk ? wg->static_identity.preshared_key : NULL);
|
|
+
|
|
+ /* e */
|
|
+ handshake_nocrypt(e, src->unencrypted_ephemeral, sizeof(src->unencrypted_ephemeral), hash);
|
|
+ if (wg->static_identity.has_psk)
|
|
+ mix_key(key, chaining_key, e, NOISE_PUBLIC_KEY_LEN);
|
|
+
|
|
+ /* es */
|
|
+ mix_dh(key, chaining_key, wg->static_identity.static_private, e);
|
|
+
|
|
+ /* s */
|
|
+ if (!handshake_decrypt(s, src->encrypted_static, sizeof(src->encrypted_static), key, hash))
|
|
+ goto out;
|
|
+
|
|
+ /* ss */
|
|
+ mix_dh(key, chaining_key, wg->static_identity.static_private, s);
|
|
+
|
|
+ /* t */
|
|
+ if (!handshake_decrypt(t, src->encrypted_timestamp, sizeof(src->encrypted_timestamp), key, hash))
|
|
+ goto out;
|
|
+
|
|
+ /* Lookup which peer we're actually talking to */
|
|
+ wg_peer = pubkey_hashtable_lookup(&wg->peer_hashtable, s);
|
|
+ if (!wg_peer)
|
|
+ goto out;
|
|
+ handshake = &wg_peer->handshake;
|
|
+ down_read(&handshake->lock);
|
|
+ replay_attack = memcmp(t, handshake->latest_timestamp, NOISE_TIMESTAMP_LEN) <= 0;
|
|
+ flood_attack = !time_is_before_jiffies64(handshake->last_initiation_consumption + INITIATIONS_PER_SECOND);
|
|
+ up_read(&handshake->lock);
|
|
+ if (replay_attack || flood_attack) {
|
|
+ peer_put(wg_peer);
|
|
+ wg_peer = NULL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /* Success! Copy everything to peer */
|
|
+ down_write(&handshake->lock);
|
|
+ memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN);
|
|
+ memcpy(handshake->latest_timestamp, t, NOISE_TIMESTAMP_LEN);
|
|
+ memcpy(handshake->key, key, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ memcpy(handshake->hash, hash, NOISE_HASH_LEN);
|
|
+ memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN);
|
|
+ handshake->remote_index = src->sender_index;
|
|
+ handshake->last_initiation_consumption = get_jiffies_64();
|
|
+ handshake->state = HANDSHAKE_CONSUMED_INITIATION;
|
|
+ up_write(&handshake->lock);
|
|
+
|
|
+out:
|
|
+ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ memzero_explicit(hash, NOISE_HASH_LEN);
|
|
+ memzero_explicit(chaining_key, NOISE_HASH_LEN);
|
|
+ up_read(&wg->static_identity.lock);
|
|
+ return wg_peer;
|
|
+}
|
|
+
|
|
+bool noise_handshake_create_response(struct message_handshake_response *dst, struct noise_handshake *handshake)
|
|
+{
|
|
+ bool ret = false;
|
|
+ down_read(&handshake->static_identity->lock);
|
|
+ down_write(&handshake->lock);
|
|
+
|
|
+ if (handshake->state != HANDSHAKE_CONSUMED_INITIATION)
|
|
+ goto out;
|
|
+
|
|
+ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE);
|
|
+ dst->receiver_index = handshake->remote_index;
|
|
+
|
|
+ /* e */
|
|
+ curve25519_generate_secret(handshake->ephemeral_private);
|
|
+ curve25519_generate_public(handshake->ephemeral_public, handshake->ephemeral_private);
|
|
+ handshake_nocrypt(dst->unencrypted_ephemeral, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN, handshake->hash);
|
|
+ if (handshake->static_identity->has_psk)
|
|
+ mix_key(handshake->key, handshake->chaining_key, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN);
|
|
+
|
|
+ /* ee */
|
|
+ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_ephemeral);
|
|
+
|
|
+ /* se */
|
|
+ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_static);
|
|
+
|
|
+ if (!handshake_encrypt(dst->encrypted_nothing, NULL, 0, handshake->key, handshake->hash))
|
|
+ goto out;
|
|
+
|
|
+ dst->sender_index = index_hashtable_insert(&handshake->entry.peer->device->index_hashtable, &handshake->entry);
|
|
+
|
|
+ handshake->state = HANDSHAKE_CREATED_RESPONSE;
|
|
+ ret = true;
|
|
+
|
|
+out:
|
|
+ up_write(&handshake->lock);
|
|
+ up_read(&handshake->static_identity->lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+struct wireguard_peer *noise_handshake_consume_response(struct message_handshake_response *src, struct wireguard_device *wg)
|
|
+{
|
|
+ struct noise_handshake *handshake;
|
|
+ struct wireguard_peer *ret_peer = NULL;
|
|
+ u8 key[NOISE_SYMMETRIC_KEY_LEN];
|
|
+ u8 hash[NOISE_HASH_LEN];
|
|
+ u8 chaining_key[NOISE_HASH_LEN];
|
|
+ u8 e[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 static_private[NOISE_PUBLIC_KEY_LEN];
|
|
+ enum noise_handshake_state state = HANDSHAKE_ZEROED;
|
|
+
|
|
+ down_read(&wg->static_identity.lock);
|
|
+
|
|
+ if (unlikely(!wg->static_identity.has_identity))
|
|
+ goto out;
|
|
+
|
|
+ handshake = (struct noise_handshake *)index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_HANDSHAKE, src->receiver_index);
|
|
+ if (unlikely(!handshake))
|
|
+ goto out;
|
|
+
|
|
+ down_read(&handshake->lock);
|
|
+ state = handshake->state;
|
|
+ memcpy(key, handshake->key, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ memcpy(hash, handshake->hash, NOISE_HASH_LEN);
|
|
+ memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN);
|
|
+ memcpy(ephemeral_private, handshake->ephemeral_private, NOISE_PUBLIC_KEY_LEN);
|
|
+ up_read(&handshake->lock);
|
|
+
|
|
+ if (state != HANDSHAKE_CREATED_INITIATION)
|
|
+ goto fail;
|
|
+
|
|
+ /* e */
|
|
+ handshake_nocrypt(e, src->unencrypted_ephemeral, sizeof(src->unencrypted_ephemeral), hash);
|
|
+ if (wg->static_identity.has_psk)
|
|
+ mix_key(key, chaining_key, e, NOISE_PUBLIC_KEY_LEN);
|
|
+
|
|
+ /* ee */
|
|
+ mix_dh(key, chaining_key, ephemeral_private, e);
|
|
+
|
|
+ /* se */
|
|
+ mix_dh(key, chaining_key, wg->static_identity.static_private, e);
|
|
+
|
|
+ /* decrypt nothing */
|
|
+ if (!handshake_decrypt(NULL, src->encrypted_nothing, sizeof(src->encrypted_nothing), key, hash))
|
|
+ goto fail;
|
|
+
|
|
+ /* Success! Copy everything to peer */
|
|
+ down_write(&handshake->lock);
|
|
+ memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN);
|
|
+ memcpy(handshake->key, key, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ memcpy(handshake->hash, hash, NOISE_HASH_LEN);
|
|
+ memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN);
|
|
+ handshake->remote_index = src->sender_index;
|
|
+ handshake->state = HANDSHAKE_CONSUMED_RESPONSE;
|
|
+ up_write(&handshake->lock);
|
|
+ ret_peer = handshake->entry.peer;
|
|
+ goto out;
|
|
+
|
|
+fail:
|
|
+ peer_put(handshake->entry.peer);
|
|
+out:
|
|
+ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN);
|
|
+ memzero_explicit(hash, NOISE_HASH_LEN);
|
|
+ memzero_explicit(chaining_key, NOISE_HASH_LEN);
|
|
+ memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN);
|
|
+ memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN);
|
|
+ up_read(&wg->static_identity.lock);
|
|
+ return ret_peer;
|
|
+}
|
|
+
|
|
+bool noise_handshake_begin_session(struct noise_handshake *handshake, struct noise_keypairs *keypairs, bool i_am_the_initiator)
|
|
+{
|
|
+ struct noise_keypair *new_keypair;
|
|
+
|
|
+ down_read(&handshake->lock);
|
|
+ if (handshake->state != HANDSHAKE_CREATED_RESPONSE && handshake->state != HANDSHAKE_CONSUMED_RESPONSE)
|
|
+ goto fail;
|
|
+
|
|
+ new_keypair = keypair_create(handshake->entry.peer);
|
|
+ if (!new_keypair)
|
|
+ goto fail;
|
|
+ new_keypair->i_am_the_initiator = i_am_the_initiator;
|
|
+ new_keypair->remote_index = handshake->remote_index;
|
|
+
|
|
+ if (i_am_the_initiator)
|
|
+ derive_keys(&new_keypair->sending, &new_keypair->receiving, handshake->chaining_key);
|
|
+ else
|
|
+ derive_keys(&new_keypair->receiving, &new_keypair->sending, handshake->chaining_key);
|
|
+ up_read(&handshake->lock);
|
|
+
|
|
+ add_new_keypair(keypairs, new_keypair);
|
|
+ index_hashtable_replace(&handshake->entry.peer->device->index_hashtable, &handshake->entry, &new_keypair->entry);
|
|
+ noise_handshake_clear(handshake);
|
|
+ net_dbg_ratelimited("Keypair %Lu created for peer %Lu\n", new_keypair->internal_id, new_keypair->entry.peer->internal_id);
|
|
+
|
|
+ return true;
|
|
+
|
|
+fail:
|
|
+ up_read(&handshake->lock);
|
|
+ return false;
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/peer.c
|
|
@@ -0,0 +1,151 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "peer.h"
|
|
+#include "device.h"
|
|
+#include "packets.h"
|
|
+#include "timers.h"
|
|
+#include "hashtables.h"
|
|
+#include "noise.h"
|
|
+
|
|
+#include <linux/kref.h>
|
|
+#include <linux/lockdep.h>
|
|
+#include <linux/rcupdate.h>
|
|
+#include <linux/list.h>
|
|
+
|
|
+static atomic64_t peer_counter = ATOMIC64_INIT(0);
|
|
+
|
|
+struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_key[NOISE_PUBLIC_KEY_LEN])
|
|
+{
|
|
+ struct wireguard_peer *peer;
|
|
+ lockdep_assert_held(&wg->device_update_lock);
|
|
+
|
|
+ if (peer_total_count(wg) >= MAX_PEERS_PER_DEVICE)
|
|
+ return NULL;
|
|
+
|
|
+ peer = kzalloc(sizeof(struct wireguard_peer), GFP_KERNEL);
|
|
+ if (!peer)
|
|
+ return NULL;
|
|
+
|
|
+ if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)) {
|
|
+ kfree(peer);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ peer->internal_id = atomic64_inc_return(&peer_counter);
|
|
+ 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);
|
|
+ skb_queue_head_init(&peer->tx_packet_queue);
|
|
+ kref_init(&peer->refcount);
|
|
+ pubkey_hashtable_add(&wg->peer_hashtable, peer);
|
|
+ list_add_tail(&peer->peer_list, &wg->peer_list);
|
|
+ pr_debug("Peer %Lu created\n", peer->internal_id);
|
|
+ return peer;
|
|
+}
|
|
+
|
|
+struct wireguard_peer *peer_get(struct wireguard_peer *peer)
|
|
+{
|
|
+ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "Calling peer_get without holding the RCU read lock.");
|
|
+ if (unlikely(!peer || !kref_get_unless_zero(&peer->refcount)))
|
|
+ return NULL;
|
|
+ return peer;
|
|
+}
|
|
+
|
|
+struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer)
|
|
+{
|
|
+ rcu_read_lock();
|
|
+ peer = peer_get(peer);
|
|
+ rcu_read_unlock();
|
|
+ return peer;
|
|
+}
|
|
+
|
|
+/* We have a separate "remove" function to get rid of the final reference because
|
|
+ * peer_list, clearing handshakes, and flushing all require mutexes which requires
|
|
+ * sleeping, which must only be done from certain contexts. */
|
|
+void peer_remove(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (unlikely(!peer))
|
|
+ return;
|
|
+ lockdep_assert_held(&peer->device->device_update_lock);
|
|
+ noise_handshake_clear(&peer->handshake);
|
|
+ noise_keypairs_clear(&peer->keypairs);
|
|
+ list_del(&peer->peer_list);
|
|
+ timers_uninit_peer(peer);
|
|
+ routing_table_remove_by_peer(&peer->device->peer_routing_table, peer);
|
|
+ pubkey_hashtable_remove(&peer->device->peer_hashtable, peer);
|
|
+ if (peer->device->workqueue)
|
|
+ flush_workqueue(peer->device->workqueue);
|
|
+ skb_queue_purge(&peer->tx_packet_queue);
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+static void rcu_release(struct rcu_head *rcu)
|
|
+{
|
|
+ struct wireguard_peer *peer = container_of(rcu, struct wireguard_peer, rcu);
|
|
+ pr_debug("Peer %Lu (%pISpfsc) destroyed\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ skb_queue_purge(&peer->tx_packet_queue);
|
|
+ dst_cache_destroy(&peer->endpoint_cache);
|
|
+ kzfree(peer);
|
|
+}
|
|
+
|
|
+static void kref_release(struct kref *refcount)
|
|
+{
|
|
+ struct wireguard_peer *peer = container_of(refcount, struct wireguard_peer, refcount);
|
|
+ call_rcu(&peer->rcu, rcu_release);
|
|
+}
|
|
+
|
|
+void peer_put(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (unlikely(!peer))
|
|
+ return;
|
|
+ kref_put(&peer->refcount, kref_release);
|
|
+}
|
|
+
|
|
+int peer_for_each_unlocked(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data)
|
|
+{
|
|
+ struct wireguard_peer *peer, *temp;
|
|
+ int ret = 0;
|
|
+
|
|
+ lockdep_assert_held(&wg->device_update_lock);
|
|
+ list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list) {
|
|
+ peer = peer_rcu_get(peer);
|
|
+ if (unlikely(!peer))
|
|
+ continue;
|
|
+ ret = fn(peer, data);
|
|
+ peer_put(peer);
|
|
+ if (ret < 0)
|
|
+ break;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int peer_for_each(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data)
|
|
+{
|
|
+ int ret;
|
|
+ mutex_lock(&wg->device_update_lock);
|
|
+ ret = peer_for_each_unlocked(wg, fn, data);
|
|
+ mutex_unlock(&wg->device_update_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void peer_remove_all(struct wireguard_device *wg)
|
|
+{
|
|
+ struct wireguard_peer *peer, *temp;
|
|
+ lockdep_assert_held(&wg->device_update_lock);
|
|
+ list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list)
|
|
+ peer_remove(peer);
|
|
+}
|
|
+
|
|
+unsigned int peer_total_count(struct wireguard_device *wg)
|
|
+{
|
|
+ unsigned int i = 0;
|
|
+ struct wireguard_peer *peer;
|
|
+ lockdep_assert_held(&wg->device_update_lock);
|
|
+ list_for_each_entry(peer, &wg->peer_list, peer_list)
|
|
+ ++i;
|
|
+ return i;
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/ratelimiter.c
|
|
@@ -0,0 +1,138 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "ratelimiter.h"
|
|
+#include "peer.h"
|
|
+#include "device.h"
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/netfilter/x_tables.h>
|
|
+#include <net/ip.h>
|
|
+
|
|
+static struct xt_match *v4_match __read_mostly;
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+static struct xt_match *v6_match __read_mostly;
|
|
+#endif
|
|
+
|
|
+enum {
|
|
+ RATELIMITER_PACKETS_PER_SECOND = 30,
|
|
+ RATELIMITER_PACKETS_BURSTABLE = 5
|
|
+};
|
|
+
|
|
+static inline void cfg_init(struct hashlimit_cfg1 *cfg, int family)
|
|
+{
|
|
+ memset(cfg, 0, sizeof(struct hashlimit_cfg1));
|
|
+ if (family == NFPROTO_IPV4)
|
|
+ cfg->srcmask = 32;
|
|
+ else if (family == NFPROTO_IPV6)
|
|
+ cfg->srcmask = 96;
|
|
+ cfg->mode = XT_HASHLIMIT_HASH_SIP; /* source IP only -- we could also do source port by ORing this with XT_HASHLIMIT_HASH_SPT */
|
|
+ cfg->avg = XT_HASHLIMIT_SCALE / RATELIMITER_PACKETS_PER_SECOND; /* 30 per second per IP */
|
|
+ cfg->burst = RATELIMITER_PACKETS_BURSTABLE; /* Allow bursts of 5 at a time */
|
|
+ cfg->gc_interval = 1000; /* same as expiration date */
|
|
+ cfg->expire = 1000; /* Units of avg (seconds = 1) times 1000 */
|
|
+ /* cfg->size and cfg->max are computed based on the memory size of left to zero */
|
|
+}
|
|
+
|
|
+int ratelimiter_init(struct ratelimiter *ratelimiter, struct wireguard_device *wg)
|
|
+{
|
|
+ struct net_device *dev = netdev_pub(wg);
|
|
+ struct xt_mtchk_param chk = { .net = wg->creating_net };
|
|
+ int ret;
|
|
+
|
|
+ memset(ratelimiter, 0, sizeof(struct ratelimiter));
|
|
+
|
|
+ cfg_init(&ratelimiter->v4_info.cfg, NFPROTO_IPV4);
|
|
+ memcpy(ratelimiter->v4_info.name, dev->name, IFNAMSIZ);
|
|
+ chk.matchinfo = &ratelimiter->v4_info;
|
|
+ chk.match = v4_match;
|
|
+ chk.family = NFPROTO_IPV4;
|
|
+ ret = v4_match->checkentry(&chk);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ cfg_init(&ratelimiter->v6_info.cfg, NFPROTO_IPV6);
|
|
+ memcpy(ratelimiter->v6_info.name, dev->name, IFNAMSIZ);
|
|
+ chk.matchinfo = &ratelimiter->v6_info;
|
|
+ chk.match = v6_match;
|
|
+ chk.family = NFPROTO_IPV6;
|
|
+ ret = v6_match->checkentry(&chk);
|
|
+ if (ret < 0) {
|
|
+ struct xt_mtdtor_param dtor_v4 = {
|
|
+ .net = wg->creating_net,
|
|
+ .match = v4_match,
|
|
+ .matchinfo = &ratelimiter->v4_info,
|
|
+ .family = NFPROTO_IPV4
|
|
+ };
|
|
+ v4_match->destroy(&dtor_v4);
|
|
+ return ret;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ ratelimiter->net = wg->creating_net;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void ratelimiter_uninit(struct ratelimiter *ratelimiter)
|
|
+{
|
|
+ struct xt_mtdtor_param dtor = { .net = ratelimiter->net };
|
|
+
|
|
+ dtor.match = v4_match;
|
|
+ dtor.matchinfo = &ratelimiter->v4_info;
|
|
+ dtor.family = NFPROTO_IPV4;
|
|
+ v4_match->destroy(&dtor);
|
|
+
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ dtor.match = v6_match;
|
|
+ dtor.matchinfo = &ratelimiter->v6_info;
|
|
+ dtor.family = NFPROTO_IPV6;
|
|
+ v6_match->destroy(&dtor);
|
|
+#endif
|
|
+}
|
|
+
|
|
+bool ratelimiter_allow(struct ratelimiter *ratelimiter, struct sk_buff *skb)
|
|
+{
|
|
+ struct xt_action_param action = { { NULL } };
|
|
+ if (unlikely(skb->len < sizeof(struct iphdr)))
|
|
+ return false;
|
|
+ if (ip_hdr(skb)->version == 4) {
|
|
+ action.match = v4_match;
|
|
+ action.matchinfo = &ratelimiter->v4_info;
|
|
+ action.thoff = ip_hdrlen(skb);
|
|
+ }
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ else if (ip_hdr(skb)->version == 6) {
|
|
+ action.match = v6_match;
|
|
+ action.matchinfo = &ratelimiter->v6_info;
|
|
+ }
|
|
+#endif
|
|
+ else
|
|
+ return false;
|
|
+ return action.match->match(skb, &action);
|
|
+}
|
|
+
|
|
+int ratelimiter_module_init(void)
|
|
+{
|
|
+ v4_match = xt_request_find_match(NFPROTO_IPV4, "hashlimit", 1);
|
|
+ if (IS_ERR(v4_match)) {
|
|
+ pr_err("The xt_hashlimit module for IPv4 is required\n");
|
|
+ return PTR_ERR(v4_match);
|
|
+ }
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ v6_match = xt_request_find_match(NFPROTO_IPV6, "hashlimit", 1);
|
|
+ if (IS_ERR(v6_match)) {
|
|
+ pr_err("The xt_hashlimit module for IPv6 is required\n");
|
|
+ module_put(v4_match->me);
|
|
+ return PTR_ERR(v6_match);
|
|
+ }
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void ratelimiter_module_deinit(void)
|
|
+{
|
|
+ module_put(v4_match->me);
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ module_put(v6_match->me);
|
|
+#endif
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/receive.c
|
|
@@ -0,0 +1,311 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "packets.h"
|
|
+#include "device.h"
|
|
+#include "peer.h"
|
|
+#include "timers.h"
|
|
+#include "messages.h"
|
|
+#include "cookie.h"
|
|
+
|
|
+#include <linux/ip.h>
|
|
+#include <linux/ipv6.h>
|
|
+#include <linux/udp.h>
|
|
+#include <net/ip_tunnels.h>
|
|
+
|
|
+static inline void rx_stats(struct wireguard_peer *peer, size_t len)
|
|
+{
|
|
+ struct pcpu_sw_netstats *tstats = get_cpu_ptr(netdev_pub(peer->device)->tstats);
|
|
+ u64_stats_update_begin(&tstats->syncp);
|
|
+ tstats->rx_bytes += len;
|
|
+ ++tstats->rx_packets;
|
|
+ u64_stats_update_end(&tstats->syncp);
|
|
+ put_cpu_ptr(tstats);
|
|
+ peer->rx_bytes += len;
|
|
+}
|
|
+
|
|
+static inline void update_latest_addr(struct wireguard_peer *peer, struct sk_buff *skb)
|
|
+{
|
|
+ struct endpoint endpoint;
|
|
+ if (!socket_endpoint_from_skb(&endpoint, skb))
|
|
+ socket_set_peer_endpoint(peer, &endpoint);
|
|
+}
|
|
+
|
|
+static inline int skb_data_offset(struct sk_buff *skb, size_t *data_offset, size_t *data_len)
|
|
+{
|
|
+ struct udphdr *udp;
|
|
+
|
|
+ if (unlikely(skb->len < sizeof(struct iphdr)))
|
|
+ return -EINVAL;
|
|
+ if (unlikely(ip_hdr(skb)->version != 4 && ip_hdr(skb)->version != 6))
|
|
+ return -EINVAL;
|
|
+ if (unlikely(ip_hdr(skb)->version == 6 && skb->len < sizeof(struct ipv6hdr)))
|
|
+ return -EINVAL;
|
|
+
|
|
+ udp = udp_hdr(skb);
|
|
+ *data_offset = (u8 *)udp - skb->data;
|
|
+ if (unlikely(*data_offset > U16_MAX)) {
|
|
+ net_dbg_skb_ratelimited("Packet has offset at impossible location from %pISpfsc\n", skb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if (unlikely(*data_offset + sizeof(struct udphdr) > skb->len)) {
|
|
+ net_dbg_skb_ratelimited("Packet isn't big enough to have UDP fields from %pISpfsc\n", skb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ *data_len = ntohs(udp->len);
|
|
+ if (unlikely(*data_len < sizeof(struct udphdr))) {
|
|
+ net_dbg_skb_ratelimited("UDP packet is reporting too small of a size from %pISpfsc\n", skb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if (unlikely(*data_len > skb->len - *data_offset)) {
|
|
+ net_dbg_skb_ratelimited("UDP packet is lying about its size from %pISpfsc\n", skb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ *data_len -= sizeof(struct udphdr);
|
|
+ *data_offset = (u8 *)udp + sizeof(struct udphdr) - skb->data;
|
|
+ if (!pskb_may_pull(skb, *data_offset + sizeof(struct message_header))) {
|
|
+ net_dbg_skb_ratelimited("Could not pull header into data section from %pISpfsc\n", skb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void receive_handshake_packet(struct wireguard_device *wg, void *data, size_t len, struct sk_buff *skb)
|
|
+{
|
|
+ struct wireguard_peer *peer = NULL;
|
|
+ enum message_type message_type;
|
|
+ bool under_load;
|
|
+ enum cookie_mac_state mac_state;
|
|
+ bool packet_needs_cookie;
|
|
+
|
|
+ message_type = message_determine_type(data, len);
|
|
+
|
|
+ if (message_type == MESSAGE_HANDSHAKE_COOKIE) {
|
|
+ net_dbg_skb_ratelimited("Receiving cookie response from %pISpfsc\n", skb);
|
|
+ cookie_message_consume(data, wg);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ under_load = skb_queue_len(&wg->incoming_handshakes) >= MAX_QUEUED_INCOMING_HANDSHAKES / 2;
|
|
+ mac_state = cookie_validate_packet(&wg->cookie_checker, skb, data, len, under_load);
|
|
+ if ((under_load && mac_state == VALID_MAC_WITH_COOKIE) || (!under_load && mac_state == VALID_MAC_BUT_NO_COOKIE))
|
|
+ packet_needs_cookie = false;
|
|
+ else if (under_load && mac_state == VALID_MAC_BUT_NO_COOKIE)
|
|
+ packet_needs_cookie = true;
|
|
+ else {
|
|
+ net_dbg_skb_ratelimited("Invalid MAC of handshake, dropping packet from %pISpfsc\n", skb);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ switch (message_type) {
|
|
+ case MESSAGE_HANDSHAKE_INITIATION:
|
|
+ if (packet_needs_cookie) {
|
|
+ struct message_handshake_initiation *message = data;
|
|
+ packet_send_handshake_cookie(wg, skb, message, sizeof(*message), message->sender_index);
|
|
+ return;
|
|
+ }
|
|
+ peer = noise_handshake_consume_initiation(data, wg);
|
|
+ if (unlikely(!peer)) {
|
|
+ net_dbg_skb_ratelimited("Invalid handshake initiation from %pISpfsc\n", skb);
|
|
+ return;
|
|
+ }
|
|
+ update_latest_addr(peer, skb);
|
|
+ net_dbg_ratelimited("Receiving handshake initiation from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ packet_send_handshake_response(peer);
|
|
+ break;
|
|
+ case MESSAGE_HANDSHAKE_RESPONSE:
|
|
+ if (packet_needs_cookie) {
|
|
+ struct message_handshake_response *message = data;
|
|
+ packet_send_handshake_cookie(wg, skb, message, sizeof(*message), message->sender_index);
|
|
+ return;
|
|
+ }
|
|
+ peer = noise_handshake_consume_response(data, wg);
|
|
+ if (unlikely(!peer)) {
|
|
+ net_dbg_skb_ratelimited("Invalid handshake response from %pISpfsc\n", skb);
|
|
+ return;
|
|
+ }
|
|
+ update_latest_addr(peer, skb);
|
|
+ net_dbg_ratelimited("Receiving handshake response from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ if (noise_handshake_begin_session(&peer->handshake, &peer->keypairs, true)) {
|
|
+ timers_ephemeral_key_created(peer);
|
|
+ timers_handshake_complete(peer);
|
|
+ peer->sent_lastminute_handshake = false;
|
|
+ /* Calling this function will either send any existing packets in the queue
|
|
+ * and not send a keepalive, which is the best case, Or, if there's nothing
|
|
+ * in the queue, it will send a keepalive, in order to give immediate
|
|
+ * confirmation of the session. */
|
|
+ packet_send_keepalive(peer);
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ WARN(1, "Somehow a wrong type of packet wound up in the handshake queue!\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ BUG_ON(!peer);
|
|
+
|
|
+ rx_stats(peer, len);
|
|
+ timers_any_authenticated_packet_received(peer);
|
|
+ timers_any_authenticated_packet_traversal(peer);
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+void packet_process_queued_handshake_packets(struct work_struct *work)
|
|
+{
|
|
+ struct wireguard_device *wg = container_of(work, struct wireguard_device, incoming_handshakes_work);
|
|
+ struct sk_buff *skb;
|
|
+ size_t len, offset;
|
|
+ size_t num_processed = 0;
|
|
+
|
|
+ while ((skb = skb_dequeue(&wg->incoming_handshakes)) != NULL) {
|
|
+ if (!skb_data_offset(skb, &offset, &len))
|
|
+ receive_handshake_packet(wg, skb->data + offset, len, skb);
|
|
+ dev_kfree_skb(skb);
|
|
+ if (++num_processed == MAX_BURST_INCOMING_HANDSHAKES) {
|
|
+ queue_work(wg->workqueue, &wg->incoming_handshakes_work);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void keep_key_fresh(struct wireguard_peer *peer)
|
|
+{
|
|
+ struct noise_keypair *keypair;
|
|
+ bool send = false;
|
|
+ if (peer->sent_lastminute_handshake)
|
|
+ return;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ keypair = rcu_dereference(peer->keypairs.current_keypair);
|
|
+ if (likely(keypair && keypair->sending.is_valid) && keypair->i_am_the_initiator &&
|
|
+ unlikely(time_is_before_eq_jiffies64(keypair->sending.birthdate + REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT)))
|
|
+ send = true;
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ if (send) {
|
|
+ peer->sent_lastminute_handshake = true;
|
|
+ packet_queue_handshake_initiation(peer);
|
|
+ }
|
|
+}
|
|
+
|
|
+struct packet_cb {
|
|
+ u8 ds;
|
|
+};
|
|
+#define PACKET_CB(skb) ((struct packet_cb *)skb->cb)
|
|
+
|
|
+static void receive_data_packet(struct sk_buff *skb, struct wireguard_peer *peer, struct endpoint *endpoint, bool used_new_key, int err)
|
|
+{
|
|
+ struct net_device *dev;
|
|
+ struct wireguard_peer *routed_peer;
|
|
+ struct wireguard_device *wg;
|
|
+
|
|
+ if (unlikely(err < 0 || !peer || !endpoint)) {
|
|
+ dev_kfree_skb(skb);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ socket_set_peer_endpoint(peer, endpoint);
|
|
+
|
|
+ wg = peer->device;
|
|
+ dev = netdev_pub(wg);
|
|
+
|
|
+ if (unlikely(used_new_key)) {
|
|
+ peer->sent_lastminute_handshake = false;
|
|
+ packet_send_queue(peer);
|
|
+ }
|
|
+
|
|
+ keep_key_fresh(peer);
|
|
+
|
|
+ /* A packet with length 0 is a keepalive packet */
|
|
+ if (unlikely(!skb->len)) {
|
|
+ net_dbg_ratelimited("Receiving keepalive packet from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ goto packet_processed;
|
|
+ }
|
|
+
|
|
+ if (!pskb_may_pull(skb, 1 /* For checking the ip version below */)) {
|
|
+ ++dev->stats.rx_errors;
|
|
+ ++dev->stats.rx_length_errors;
|
|
+ net_dbg_ratelimited("Packet missing IP version from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ goto packet_processed;
|
|
+ }
|
|
+
|
|
+ skb->dev = dev;
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
+ if (skb->len >= sizeof(struct iphdr) && ip_hdr(skb)->version == 4) {
|
|
+ skb->protocol = htons(ETH_P_IP);
|
|
+ if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
|
|
+ IP_ECN_set_ce(ip_hdr(skb));
|
|
+ } else if (skb->len >= sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6) {
|
|
+ skb->protocol = htons(ETH_P_IPV6);
|
|
+ if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
|
|
+ IP6_ECN_set_ce(skb, ipv6_hdr(skb));
|
|
+ } else {
|
|
+ ++dev->stats.rx_errors;
|
|
+ ++dev->stats.rx_length_errors;
|
|
+ net_dbg_ratelimited("Packet neither ipv4 nor ipv6 from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ goto packet_processed;
|
|
+ }
|
|
+
|
|
+ timers_data_received(peer);
|
|
+
|
|
+ routed_peer = routing_table_lookup_src(&wg->peer_routing_table, skb);
|
|
+ peer_put(routed_peer); /* We don't need the extra reference. */
|
|
+
|
|
+ if (unlikely(routed_peer != peer)) {
|
|
+ ++dev->stats.rx_errors;
|
|
+ ++dev->stats.rx_frame_errors;
|
|
+ net_dbg_skb_ratelimited("Packet has unallowed src IP (%pISc) from peer %Lu (%pISpfsc)\n", skb, peer->internal_id, &peer->endpoint.addr);
|
|
+ goto packet_processed;
|
|
+ }
|
|
+
|
|
+ if (likely(netif_rx(skb) == NET_RX_SUCCESS))
|
|
+ rx_stats(peer, skb->len);
|
|
+ else {
|
|
+ ++dev->stats.rx_dropped;
|
|
+ net_dbg_ratelimited("Failed to give packet to userspace from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ }
|
|
+ goto continue_processing;
|
|
+
|
|
+packet_processed:
|
|
+ dev_kfree_skb(skb);
|
|
+continue_processing:
|
|
+ timers_any_authenticated_packet_received(peer);
|
|
+ timers_any_authenticated_packet_traversal(peer);
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+void packet_receive(struct wireguard_device *wg, struct sk_buff *skb)
|
|
+{
|
|
+ size_t len, offset;
|
|
+
|
|
+ if (unlikely(skb_data_offset(skb, &offset, &len) < 0))
|
|
+ goto err;
|
|
+ switch (message_determine_type(skb->data + offset, len)) {
|
|
+ case MESSAGE_HANDSHAKE_INITIATION:
|
|
+ case MESSAGE_HANDSHAKE_RESPONSE:
|
|
+ case MESSAGE_HANDSHAKE_COOKIE:
|
|
+ if (skb_queue_len(&wg->incoming_handshakes) > MAX_QUEUED_INCOMING_HANDSHAKES) {
|
|
+ net_dbg_skb_ratelimited("Too many handshakes queued, dropping packet from %pISpfsc\n", skb);
|
|
+ goto err;
|
|
+ }
|
|
+ if (skb_linearize(skb) < 0) {
|
|
+ net_dbg_skb_ratelimited("Unable to linearize handshake skb from %pISpfsc\n", skb);
|
|
+ goto err;
|
|
+ }
|
|
+ skb_queue_tail(&wg->incoming_handshakes, skb);
|
|
+ /* Queues up a call to packet_process_queued_handshake_packets(skb): */
|
|
+ queue_work(wg->workqueue, &wg->incoming_handshakes_work);
|
|
+ break;
|
|
+ case MESSAGE_DATA:
|
|
+ PACKET_CB(skb)->ds = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
|
|
+ packet_consume_data(skb, offset, wg, receive_data_packet);
|
|
+ break;
|
|
+ default:
|
|
+ net_dbg_skb_ratelimited("Invalid packet from %pISpfsc\n", skb);
|
|
+ goto err;
|
|
+ }
|
|
+ return;
|
|
+
|
|
+err:
|
|
+ dev_kfree_skb(skb);
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/routingtable.c
|
|
@@ -0,0 +1,516 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "routingtable.h"
|
|
+#include "peer.h"
|
|
+
|
|
+struct routing_table_node {
|
|
+ struct routing_table_node __rcu *bit[2];
|
|
+ struct rcu_head rcu;
|
|
+ struct wireguard_peer *peer;
|
|
+ u8 cidr;
|
|
+ u8 bit_at_a, bit_at_b;
|
|
+ bool incidental;
|
|
+ u8 bits[];
|
|
+};
|
|
+
|
|
+static inline u8 bit_at(const u8 *key, u8 a, u8 b)
|
|
+{
|
|
+ return (key[a] >> b) & 1;
|
|
+}
|
|
+static inline void copy_and_assign_cidr(struct routing_table_node *node, const u8 *src, u8 cidr)
|
|
+{
|
|
+ memcpy(node->bits, src, (cidr + 7) / 8);
|
|
+ node->bits[(cidr + 7) / 8 - 1] &= 0xff << ((8 - (cidr % 8)) % 8);
|
|
+ node->cidr = cidr;
|
|
+ node->bit_at_a = cidr / 8;
|
|
+ node->bit_at_b = 7 - (cidr % 8);
|
|
+}
|
|
+
|
|
+/* Non-recursive RCU expansion of:
|
|
+ *
|
|
+ * free_node(node)
|
|
+ * {
|
|
+ * if (!node)
|
|
+ * return;
|
|
+ * free_node(node->bit[0]);
|
|
+ * free_node(node->bit[1]);
|
|
+ * kfree_rcu(node);
|
|
+ * }
|
|
+ */
|
|
+#define ref(p) rcu_access_pointer(p)
|
|
+#define push(p) do { BUG_ON(len >= 128); stack[len++] = rcu_dereference_protected(p, lockdep_is_held(lock)); } while (0)
|
|
+static void free_node(struct routing_table_node *top, struct mutex *lock)
|
|
+{
|
|
+ struct routing_table_node *stack[128];
|
|
+ struct routing_table_node *node = NULL;
|
|
+ struct routing_table_node *prev = NULL;
|
|
+ unsigned int len = 0;
|
|
+
|
|
+ if (!top)
|
|
+ return;
|
|
+
|
|
+ stack[len++] = top;
|
|
+ while (len > 0) {
|
|
+ node = stack[len - 1];
|
|
+ if (!prev || ref(prev->bit[0]) == node || ref(prev->bit[1]) == node) {
|
|
+ if (ref(node->bit[0]))
|
|
+ push(node->bit[0]);
|
|
+ else if (ref(node->bit[1]))
|
|
+ push(node->bit[1]);
|
|
+ } else if (ref(node->bit[0]) == prev) {
|
|
+ if (ref(node->bit[1]))
|
|
+ push(node->bit[1]);
|
|
+ } else {
|
|
+ kfree_rcu(node, rcu);
|
|
+ --len;
|
|
+ }
|
|
+ prev = node;
|
|
+ }
|
|
+}
|
|
+#undef push
|
|
+#define push(p) do { BUG_ON(len >= 128); stack[len++] = p; } while (0)
|
|
+static bool walk_remove_by_peer(struct routing_table_node __rcu **top, struct wireguard_peer *peer, struct mutex *lock)
|
|
+{
|
|
+ struct routing_table_node __rcu **stack[128];
|
|
+ struct routing_table_node __rcu **nptr;
|
|
+ struct routing_table_node *node = NULL;
|
|
+ struct routing_table_node *prev = NULL;
|
|
+ unsigned int len = 0;
|
|
+ bool ret = false;
|
|
+
|
|
+ stack[len++] = top;
|
|
+ while (len > 0) {
|
|
+ nptr = stack[len - 1];
|
|
+ node = rcu_dereference_protected(*nptr, lockdep_is_held(lock));
|
|
+ if (!node) {
|
|
+ --len;
|
|
+ continue;
|
|
+ }
|
|
+ if (!prev || ref(prev->bit[0]) == node || ref(prev->bit[1]) == node) {
|
|
+ if (ref(node->bit[0]))
|
|
+ push(&node->bit[0]);
|
|
+ else if (ref(node->bit[1]))
|
|
+ push(&node->bit[1]);
|
|
+ } else if (ref(node->bit[0]) == prev) {
|
|
+ if (ref(node->bit[1]))
|
|
+ push(&node->bit[1]);
|
|
+ } else {
|
|
+ if (node->peer == peer) {
|
|
+ ret = true;
|
|
+ node->peer = NULL;
|
|
+ node->incidental = true;
|
|
+ if (!node->bit[0] || !node->bit[1]) {
|
|
+ /* collapse (even if both are null) */
|
|
+ rcu_assign_pointer(*nptr, rcu_dereference_protected(node->bit[!node->bit[0]], lockdep_is_held(lock)));
|
|
+ rcu_assign_pointer(node->bit[0], NULL);
|
|
+ rcu_assign_pointer(node->bit[1], NULL);
|
|
+ free_node(node, lock);
|
|
+ }
|
|
+ }
|
|
+ --len;
|
|
+ }
|
|
+ prev = node;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+#undef ref
|
|
+#undef push
|
|
+
|
|
+static inline bool match(const struct routing_table_node *node, const u8 *key, u8 match_len)
|
|
+{
|
|
+ u8 full_blocks_to_match = match_len / 8;
|
|
+ u8 bits_leftover = match_len % 8;
|
|
+ u8 mask;
|
|
+ const u8 *a = node->bits, *b = key;
|
|
+ if (memcmp(a, b, full_blocks_to_match))
|
|
+ return false;
|
|
+ if (!bits_leftover)
|
|
+ return true;
|
|
+ mask = ~(0xff >> bits_leftover);
|
|
+ return (a[full_blocks_to_match] & mask) == (b[full_blocks_to_match] & mask);
|
|
+}
|
|
+
|
|
+static inline u8 common_bits(const struct routing_table_node *node, const u8 *key, u8 match_len)
|
|
+{
|
|
+ u8 max = (((match_len > node->cidr) ? match_len : node->cidr) + 7) / 8;
|
|
+ u8 bits = 0;
|
|
+ u8 i, mask;
|
|
+ const u8 *a = node->bits, *b = key;
|
|
+ for (i = 0; i < max; ++i, bits += 8) {
|
|
+ if (a[i] != b[i])
|
|
+ break;
|
|
+ }
|
|
+ if (i == max)
|
|
+ return bits;
|
|
+ for (mask = 128; mask > 0; mask /= 2, ++bits) {
|
|
+ if ((a[i] & mask) != (b[i] & mask))
|
|
+ return bits;
|
|
+ }
|
|
+ BUG();
|
|
+ return bits;
|
|
+}
|
|
+
|
|
+static int remove(struct routing_table_node __rcu **trie, const u8 *key, u8 cidr, struct mutex *lock)
|
|
+{
|
|
+ struct routing_table_node *parent = NULL, *node;
|
|
+ node = rcu_dereference_protected(*trie, lockdep_is_held(lock));
|
|
+ while (node && node->cidr <= cidr && match(node, key, node->cidr)) {
|
|
+ if (node->cidr == cidr) {
|
|
+ /* exact match */
|
|
+ node->incidental = true;
|
|
+ node->peer = NULL;
|
|
+ if (!node->bit[0] || !node->bit[1]) {
|
|
+ /* collapse (even if both are null) */
|
|
+ if (parent)
|
|
+ rcu_assign_pointer(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)],
|
|
+ rcu_dereference_protected(node->bit[(!node->bit[0]) ? 1 : 0], lockdep_is_held(lock)));
|
|
+ rcu_assign_pointer(node->bit[0], NULL);
|
|
+ rcu_assign_pointer(node->bit[1], NULL);
|
|
+ free_node(node, lock);
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+ parent = node;
|
|
+ node = rcu_dereference_protected(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)], lockdep_is_held(lock));
|
|
+ }
|
|
+ return -ENOENT;
|
|
+}
|
|
+
|
|
+static inline struct routing_table_node *find_node(struct routing_table_node *trie, u8 bits, const u8 *key)
|
|
+{
|
|
+ struct routing_table_node *node = trie, *found = NULL;
|
|
+ while (node && match(node, key, node->cidr)) {
|
|
+ if (!node->incidental)
|
|
+ found = node;
|
|
+ if (node->cidr == bits)
|
|
+ break;
|
|
+ node = rcu_dereference(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)]);
|
|
+ }
|
|
+ return found;
|
|
+}
|
|
+
|
|
+static inline bool node_placement(struct routing_table_node __rcu *trie, const u8 *key, u8 cidr, struct routing_table_node **rnode, struct mutex *lock)
|
|
+{
|
|
+ bool exact = false;
|
|
+ struct routing_table_node *parent = NULL, *node = rcu_dereference_protected(trie, lockdep_is_held(lock));
|
|
+ while (node && node->cidr <= cidr && match(node, key, node->cidr)) {
|
|
+ parent = node;
|
|
+ if (parent->cidr == cidr) {
|
|
+ exact = true;
|
|
+ break;
|
|
+ }
|
|
+ node = rcu_dereference_protected(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)], lockdep_is_held(lock));
|
|
+ }
|
|
+ if (rnode)
|
|
+ *rnode = parent;
|
|
+ return exact;
|
|
+}
|
|
+
|
|
+static int add(struct routing_table_node __rcu **trie, u8 bits, const u8 *key, u8 cidr, struct wireguard_peer *peer, struct mutex *lock)
|
|
+{
|
|
+ struct routing_table_node *node, *parent, *down, *newnode;
|
|
+
|
|
+ if (!rcu_access_pointer(*trie)) {
|
|
+ node = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL);
|
|
+ if (!node)
|
|
+ return -ENOMEM;
|
|
+ node->peer = peer;
|
|
+ copy_and_assign_cidr(node, key, cidr);
|
|
+ rcu_assign_pointer(*trie, node);
|
|
+ return 0;
|
|
+ }
|
|
+ if (node_placement(*trie, key, cidr, &node, lock)) {
|
|
+ /* exact match */
|
|
+ node->incidental = false;
|
|
+ node->peer = peer;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ newnode = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL);
|
|
+ if (!newnode)
|
|
+ return -ENOMEM;
|
|
+ newnode->peer = peer;
|
|
+ copy_and_assign_cidr(newnode, key, cidr);
|
|
+
|
|
+ if (!node)
|
|
+ down = rcu_dereference_protected(*trie, lockdep_is_held(lock));
|
|
+ else
|
|
+ down = rcu_dereference_protected(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)], lockdep_is_held(lock));
|
|
+ if (!down) {
|
|
+ rcu_assign_pointer(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)], newnode);
|
|
+ return 0;
|
|
+ }
|
|
+ /* here we must be inserting between node and down */
|
|
+ cidr = min(cidr, common_bits(down, key, cidr));
|
|
+ parent = node;
|
|
+
|
|
+ /* we either need to make a new branch above down and newnode
|
|
+ * or newnode can be the branch. newnode can be the branch if
|
|
+ * its cidr == bits_in_common */
|
|
+ if (newnode->cidr == cidr) {
|
|
+ /* newnode can be the branch */
|
|
+ rcu_assign_pointer(newnode->bit[bit_at(down->bits, newnode->bit_at_a, newnode->bit_at_b)], down);
|
|
+ if (!parent)
|
|
+ rcu_assign_pointer(*trie, newnode);
|
|
+ else
|
|
+ rcu_assign_pointer(parent->bit[bit_at(newnode->bits, parent->bit_at_a, parent->bit_at_b)], newnode);
|
|
+ } else {
|
|
+ /* reparent */
|
|
+ node = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL);
|
|
+ if (!node) {
|
|
+ kfree(newnode);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ node->incidental = true;
|
|
+ copy_and_assign_cidr(node, newnode->bits, cidr);
|
|
+
|
|
+ rcu_assign_pointer(node->bit[bit_at(down->bits, node->bit_at_a, node->bit_at_b)], down);
|
|
+ rcu_assign_pointer(node->bit[bit_at(newnode->bits, node->bit_at_a, node->bit_at_b)], newnode);
|
|
+ if (!parent)
|
|
+ rcu_assign_pointer(*trie, node);
|
|
+ else
|
|
+ rcu_assign_pointer(parent->bit[bit_at(node->bits, parent->bit_at_a, parent->bit_at_b)], node);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#define push(p) do { \
|
|
+ struct routing_table_node *next = (maybe_lock ? rcu_dereference_protected(p, lockdep_is_held(maybe_lock)) : rcu_dereference(p)); \
|
|
+ if (next) { \
|
|
+ BUG_ON(len >= 128); \
|
|
+ stack[len++] = next; \
|
|
+ } \
|
|
+} while (0)
|
|
+static int walk_ips(struct routing_table_node *top, int family, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family), struct mutex *maybe_lock)
|
|
+{
|
|
+ int ret;
|
|
+ union nf_inet_addr ip = { .all = { 0 } };
|
|
+ struct routing_table_node *stack[128];
|
|
+ struct routing_table_node *node;
|
|
+ unsigned int len = 0;
|
|
+ struct wireguard_peer *peer;
|
|
+
|
|
+ if (!top)
|
|
+ return 0;
|
|
+
|
|
+ stack[len++] = top;
|
|
+ while (len > 0) {
|
|
+ node = stack[--len];
|
|
+
|
|
+ peer = peer_get(node->peer);
|
|
+ if (peer) {
|
|
+ memcpy(ip.all, node->bits, family == AF_INET6 ? 16 : 4);
|
|
+ ret = func(ctx, peer, ip, node->cidr, family);
|
|
+ peer_put(peer);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ push(node->bit[0]);
|
|
+ push(node->bit[1]);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+static int walk_ips_by_peer(struct routing_table_node *top, int family, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family), struct mutex *maybe_lock)
|
|
+{
|
|
+ int ret;
|
|
+ union nf_inet_addr ip = { .all = { 0 } };
|
|
+ struct routing_table_node *stack[128];
|
|
+ struct routing_table_node *node;
|
|
+ unsigned int len = 0;
|
|
+
|
|
+ if (!top)
|
|
+ return 0;
|
|
+
|
|
+ stack[len++] = top;
|
|
+ while (len > 0) {
|
|
+ node = stack[--len];
|
|
+
|
|
+ if (node->peer == peer) {
|
|
+ memcpy(ip.all, node->bits, family == AF_INET6 ? 16 : 4);
|
|
+ ret = func(ctx, ip, node->cidr, family);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ push(node->bit[0]);
|
|
+ push(node->bit[1]);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+#undef push
|
|
+
|
|
+void routing_table_init(struct routing_table *table)
|
|
+{
|
|
+ memset(table, 0, sizeof(struct routing_table));
|
|
+ mutex_init(&table->table_update_lock);
|
|
+}
|
|
+
|
|
+void routing_table_free(struct routing_table *table)
|
|
+{
|
|
+ mutex_lock(&table->table_update_lock);
|
|
+ free_node(rcu_dereference_protected(table->root4, lockdep_is_held(&table->table_update_lock)), &table->table_update_lock);
|
|
+ rcu_assign_pointer(table->root4, NULL);
|
|
+ free_node(rcu_dereference_protected(table->root6, lockdep_is_held(&table->table_update_lock)), &table->table_update_lock);
|
|
+ rcu_assign_pointer(table->root6, NULL);
|
|
+ mutex_unlock(&table->table_update_lock);
|
|
+}
|
|
+
|
|
+int routing_table_insert_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr, struct wireguard_peer *peer)
|
|
+{
|
|
+ int ret;
|
|
+ if (cidr > 32)
|
|
+ return -EINVAL;
|
|
+ mutex_lock(&table->table_update_lock);
|
|
+ ret = add(&table->root4, 32, (const u8 *)ip, cidr, peer, &table->table_update_lock);
|
|
+ mutex_unlock(&table->table_update_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int routing_table_insert_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr, struct wireguard_peer *peer)
|
|
+{
|
|
+ int ret;
|
|
+ if (cidr > 128)
|
|
+ return -EINVAL;
|
|
+ mutex_lock(&table->table_update_lock);
|
|
+ ret = add(&table->root6, 128, (const u8 *)ip, cidr, peer, &table->table_update_lock);
|
|
+ mutex_unlock(&table->table_update_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* Returns a strong reference to a peer */
|
|
+inline struct wireguard_peer *routing_table_lookup_v4(struct routing_table *table, const struct in_addr *ip)
|
|
+{
|
|
+ struct wireguard_peer *peer = NULL;
|
|
+ struct routing_table_node *node;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ node = find_node(rcu_dereference(table->root4), 32, (const u8 *)ip);
|
|
+ if (node)
|
|
+ peer = peer_get(node->peer);
|
|
+ rcu_read_unlock();
|
|
+ return peer;
|
|
+}
|
|
+
|
|
+/* Returns a strong reference to a peer */
|
|
+inline struct wireguard_peer *routing_table_lookup_v6(struct routing_table *table, const struct in6_addr *ip)
|
|
+{
|
|
+ struct wireguard_peer *peer = NULL;
|
|
+ struct routing_table_node *node;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ node = find_node(rcu_dereference(table->root6), 128, (const u8 *)ip);
|
|
+ if (node)
|
|
+ peer = peer_get(node->peer);
|
|
+ rcu_read_unlock();
|
|
+ return peer;
|
|
+}
|
|
+
|
|
+int routing_table_remove_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr)
|
|
+{
|
|
+ int ret;
|
|
+ mutex_lock(&table->table_update_lock);
|
|
+ ret = remove(&table->root4, (const u8 *)ip, cidr, &table->table_update_lock);
|
|
+ mutex_unlock(&table->table_update_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int routing_table_remove_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr)
|
|
+{
|
|
+ int ret;
|
|
+ mutex_lock(&table->table_update_lock);
|
|
+ ret = remove(&table->root6, (const u8 *)ip, cidr, &table->table_update_lock);
|
|
+ mutex_unlock(&table->table_update_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int routing_table_remove_by_peer(struct routing_table *table, struct wireguard_peer *peer)
|
|
+{
|
|
+ bool found;
|
|
+ mutex_lock(&table->table_update_lock);
|
|
+ found = walk_remove_by_peer(&table->root4, peer, &table->table_update_lock) | walk_remove_by_peer(&table->root6, peer, &table->table_update_lock);
|
|
+ mutex_unlock(&table->table_update_lock);
|
|
+ return found ? 0 : -EINVAL;
|
|
+}
|
|
+
|
|
+/* Calls func with a strong reference to each peer, before putting it when the function has completed.
|
|
+ * It's thus up to the caller to call peer_put on it if it's going to be used elsewhere after or stored. */
|
|
+int routing_table_walk_ips(struct routing_table *table, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family))
|
|
+{
|
|
+ int ret;
|
|
+ rcu_read_lock();
|
|
+ ret = walk_ips(rcu_dereference(table->root4), AF_INET, ctx, func, NULL);
|
|
+ rcu_read_unlock();
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ rcu_read_lock();
|
|
+ ret = walk_ips(rcu_dereference(table->root6), AF_INET6, ctx, func, NULL);
|
|
+ rcu_read_unlock();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int routing_table_walk_ips_by_peer(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family))
|
|
+{
|
|
+ int ret;
|
|
+ rcu_read_lock();
|
|
+ ret = walk_ips_by_peer(rcu_dereference(table->root4), AF_INET, ctx, peer, func, NULL);
|
|
+ rcu_read_unlock();
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ rcu_read_lock();
|
|
+ ret = walk_ips_by_peer(rcu_dereference(table->root6), AF_INET6, ctx, peer, func, NULL);
|
|
+ rcu_read_unlock();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int routing_table_walk_ips_by_peer_sleepable(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family))
|
|
+{
|
|
+ int ret;
|
|
+ mutex_lock(&table->table_update_lock);
|
|
+ ret = walk_ips_by_peer(rcu_dereference_protected(table->root4, lockdep_is_held(&table->table_update_lock)), AF_INET, ctx, peer, func, &table->table_update_lock);
|
|
+ mutex_unlock(&table->table_update_lock);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ mutex_lock(&table->table_update_lock);
|
|
+ ret = walk_ips_by_peer(rcu_dereference_protected(table->root6, lockdep_is_held(&table->table_update_lock)), AF_INET6, ctx, peer, func, &table->table_update_lock);
|
|
+ mutex_unlock(&table->table_update_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static inline bool has_valid_ip_header(struct sk_buff *skb)
|
|
+{
|
|
+ if (unlikely(skb->len < sizeof(struct iphdr)))
|
|
+ return false;
|
|
+ else if (unlikely(skb->len < sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6))
|
|
+ return false;
|
|
+ else if (unlikely(ip_hdr(skb)->version != 4 && ip_hdr(skb)->version != 6))
|
|
+ return false;
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/* Returns a strong reference to a peer */
|
|
+struct wireguard_peer *routing_table_lookup_dst(struct routing_table *table, struct sk_buff *skb)
|
|
+{
|
|
+ if (unlikely(!has_valid_ip_header(skb)))
|
|
+ return NULL;
|
|
+ if (ip_hdr(skb)->version == 4)
|
|
+ return routing_table_lookup_v4(table, (struct in_addr *)&ip_hdr(skb)->daddr);
|
|
+ else if (ip_hdr(skb)->version == 6)
|
|
+ return routing_table_lookup_v6(table, &ipv6_hdr(skb)->daddr);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/* Returns a strong reference to a peer */
|
|
+struct wireguard_peer *routing_table_lookup_src(struct routing_table *table, struct sk_buff *skb)
|
|
+{
|
|
+ if (unlikely(!has_valid_ip_header(skb)))
|
|
+ return NULL;
|
|
+ if (ip_hdr(skb)->version == 4)
|
|
+ return routing_table_lookup_v4(table, (struct in_addr *)&ip_hdr(skb)->saddr);
|
|
+ else if (ip_hdr(skb)->version == 6)
|
|
+ return routing_table_lookup_v6(table, &ipv6_hdr(skb)->saddr);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+#include "selftest/routing-table.h"
|
|
--- /dev/null
|
|
+++ b/net/wireguard/send.c
|
|
@@ -0,0 +1,192 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "packets.h"
|
|
+#include "timers.h"
|
|
+#include "device.h"
|
|
+#include "peer.h"
|
|
+#include "socket.h"
|
|
+#include "messages.h"
|
|
+#include "cookie.h"
|
|
+
|
|
+#include <linux/uio.h>
|
|
+#include <linux/inetdevice.h>
|
|
+#include <linux/socket.h>
|
|
+#include <linux/jiffies.h>
|
|
+#include <net/udp.h>
|
|
+#include <net/sock.h>
|
|
+
|
|
+static void packet_send_handshake_initiation(struct wireguard_peer *peer)
|
|
+{
|
|
+ struct message_handshake_initiation packet;
|
|
+
|
|
+ down_write(&peer->handshake.lock);
|
|
+ if (!time_is_before_jiffies64(peer->last_sent_handshake + REKEY_TIMEOUT)) {
|
|
+ up_write(&peer->handshake.lock);
|
|
+ return; /* This function is rate limited. */
|
|
+ }
|
|
+ peer->last_sent_handshake = get_jiffies_64();
|
|
+ up_write(&peer->handshake.lock);
|
|
+
|
|
+ net_dbg_ratelimited("Sending handshake initiation to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+
|
|
+ if (noise_handshake_create_initiation(&packet, &peer->handshake)) {
|
|
+ cookie_add_mac_to_packet(&packet, sizeof(packet), peer);
|
|
+ timers_any_authenticated_packet_traversal(peer);
|
|
+ socket_send_buffer_to_peer(peer, &packet, sizeof(struct message_handshake_initiation), HANDSHAKE_DSCP);
|
|
+ timers_handshake_initiated(peer);
|
|
+ }
|
|
+}
|
|
+
|
|
+void packet_send_queued_handshakes(struct work_struct *work)
|
|
+{
|
|
+ struct wireguard_peer *peer = container_of(work, struct wireguard_peer, transmit_handshake_work);
|
|
+ packet_send_handshake_initiation(peer);
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+void packet_queue_handshake_initiation(struct wireguard_peer *peer)
|
|
+{
|
|
+ /* First checking the timestamp here is just an optimization; it will
|
|
+ * be caught while properly locked inside the actual work queue. */
|
|
+ if (!time_is_before_jiffies64(peer->last_sent_handshake + REKEY_TIMEOUT))
|
|
+ return;
|
|
+
|
|
+ peer = peer_rcu_get(peer);
|
|
+ if (unlikely(!peer))
|
|
+ return;
|
|
+
|
|
+ /* Queues up calling packet_send_queued_handshakes(peer), where we do a peer_put(peer) after: */
|
|
+ if (!queue_work(peer->device->workqueue, &peer->transmit_handshake_work))
|
|
+ peer_put(peer); /* If the work was already queued, we want to drop the extra reference */
|
|
+}
|
|
+
|
|
+void packet_send_handshake_response(struct wireguard_peer *peer)
|
|
+{
|
|
+ struct message_handshake_response packet;
|
|
+
|
|
+ net_dbg_ratelimited("Sending handshake response to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ peer->last_sent_handshake = get_jiffies_64();
|
|
+
|
|
+ if (noise_handshake_create_response(&packet, &peer->handshake)) {
|
|
+ cookie_add_mac_to_packet(&packet, sizeof(packet), peer);
|
|
+ if (noise_handshake_begin_session(&peer->handshake, &peer->keypairs, false)) {
|
|
+ timers_ephemeral_key_created(peer);
|
|
+ timers_any_authenticated_packet_traversal(peer);
|
|
+ socket_send_buffer_to_peer(peer, &packet, sizeof(struct message_handshake_response), HANDSHAKE_DSCP);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *initiating_skb, void *data, size_t data_len, __le32 sender_index)
|
|
+{
|
|
+ struct message_handshake_cookie packet;
|
|
+
|
|
+ net_dbg_skb_ratelimited("Sending cookie response for denied handshake message for %pISpfsc\n", initiating_skb);
|
|
+ cookie_message_create(&packet, initiating_skb, data, data_len, sender_index, &wg->cookie_checker);
|
|
+ socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet, sizeof(packet));
|
|
+}
|
|
+
|
|
+static inline void keep_key_fresh(struct wireguard_peer *peer)
|
|
+{
|
|
+ struct noise_keypair *keypair;
|
|
+ bool send = false;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ keypair = rcu_dereference(peer->keypairs.current_keypair);
|
|
+ if (likely(keypair && keypair->sending.is_valid) &&
|
|
+ (unlikely(atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES) ||
|
|
+ (keypair->i_am_the_initiator && unlikely(time_is_before_eq_jiffies64(keypair->sending.birthdate + REKEY_AFTER_TIME)))))
|
|
+ send = true;
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ if (send)
|
|
+ packet_queue_handshake_initiation(peer);
|
|
+}
|
|
+
|
|
+void packet_send_keepalive(struct wireguard_peer *peer)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+ if (!skb_queue_len(&peer->tx_packet_queue)) {
|
|
+ skb = alloc_skb(DATA_PACKET_HEAD_ROOM + MESSAGE_MINIMUM_LENGTH, GFP_ATOMIC);
|
|
+ if (unlikely(!skb))
|
|
+ return;
|
|
+ skb_reserve(skb, DATA_PACKET_HEAD_ROOM);
|
|
+ skb->dev = netdev_pub(peer->device);
|
|
+ skb_queue_tail(&peer->tx_packet_queue, skb);
|
|
+ net_dbg_ratelimited("Sending keepalive packet to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr);
|
|
+ }
|
|
+ packet_send_queue(peer);
|
|
+}
|
|
+
|
|
+static void message_create_data_done(struct sk_buff_head *queue, struct wireguard_peer *peer)
|
|
+{
|
|
+ struct sk_buff *skb, *tmp;
|
|
+ bool is_keepalive, data_sent = false;
|
|
+
|
|
+ timers_any_authenticated_packet_traversal(peer);
|
|
+ skb_queue_walk_safe(queue, skb, tmp) {
|
|
+ is_keepalive = skb->len == message_data_len(0);
|
|
+ if (likely(!socket_send_skb_to_peer(peer, skb, *(u8 *)skb->cb) && !is_keepalive))
|
|
+ data_sent = true;
|
|
+ }
|
|
+ if (likely(data_sent))
|
|
+ timers_data_sent(peer);
|
|
+
|
|
+ keep_key_fresh(peer);
|
|
+
|
|
+ if (unlikely(peer->need_resend_queue))
|
|
+ packet_send_queue(peer);
|
|
+}
|
|
+
|
|
+void packet_send_queue(struct wireguard_peer *peer)
|
|
+{
|
|
+ struct sk_buff_head queue;
|
|
+ unsigned long flags;
|
|
+
|
|
+ peer->need_resend_queue = false;
|
|
+
|
|
+ /* Steal the current queue into our local one. */
|
|
+ skb_queue_head_init(&queue);
|
|
+ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags);
|
|
+ skb_queue_splice_init(&peer->tx_packet_queue, &queue);
|
|
+ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags);
|
|
+
|
|
+ if (unlikely(!skb_queue_len(&queue)))
|
|
+ return;
|
|
+
|
|
+ /* We submit it for encryption and sending. */
|
|
+ switch (packet_create_data(&queue, peer, message_create_data_done)) {
|
|
+ case 0:
|
|
+ break;
|
|
+ case -EBUSY:
|
|
+ /* EBUSY happens when the parallel workers are all filled up, in which
|
|
+ * case we should requeue everything. */
|
|
+
|
|
+ /* First, we mark that we should try to do this later, when existing
|
|
+ * jobs are done. */
|
|
+ peer->need_resend_queue = true;
|
|
+
|
|
+ /* We stick the remaining skbs from local_queue at the top of the peer's
|
|
+ * queue again, setting the top of local_queue to be the skb that begins
|
|
+ * the requeueing. */
|
|
+ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags);
|
|
+ skb_queue_splice(&queue, &peer->tx_packet_queue);
|
|
+ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags);
|
|
+ break;
|
|
+ case -ENOKEY:
|
|
+ /* ENOKEY means that we don't have a valid session for the peer, which
|
|
+ * means we should initiate a session, but after requeuing like above. */
|
|
+
|
|
+ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags);
|
|
+ skb_queue_splice(&queue, &peer->tx_packet_queue);
|
|
+ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags);
|
|
+
|
|
+ packet_queue_handshake_initiation(peer);
|
|
+ break;
|
|
+ default:
|
|
+ /* If we failed for any other reason, we want to just free the packets and
|
|
+ * forget about them. We do this unlocked, since we're the only ones with
|
|
+ * a reference to the local queue. */
|
|
+ __skb_queue_purge(&queue);
|
|
+ }
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/socket.c
|
|
@@ -0,0 +1,385 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "device.h"
|
|
+#include "peer.h"
|
|
+#include "socket.h"
|
|
+#include "packets.h"
|
|
+#include "messages.h"
|
|
+
|
|
+#include <linux/ctype.h>
|
|
+#include <linux/net.h>
|
|
+#include <linux/if_vlan.h>
|
|
+#include <linux/if_ether.h>
|
|
+#include <net/udp_tunnel.h>
|
|
+#include <net/ipv6.h>
|
|
+
|
|
+static inline int send4(struct wireguard_device *wg, struct sk_buff *skb, struct endpoint *endpoint, u8 ds, struct dst_cache *cache)
|
|
+{
|
|
+ struct flowi4 fl = {
|
|
+ .saddr = endpoint->src4.s_addr,
|
|
+ .daddr = endpoint->addr4.sin_addr.s_addr,
|
|
+ .fl4_dport = endpoint->addr4.sin_port,
|
|
+ .fl4_sport = htons(wg->incoming_port),
|
|
+ .flowi4_mark = wg->fwmark,
|
|
+ .flowi4_proto = IPPROTO_UDP
|
|
+ };
|
|
+ struct rtable *rt = NULL;
|
|
+ struct sock *sock;
|
|
+ int ret = 0;
|
|
+
|
|
+ skb->next = skb->prev = NULL;
|
|
+ skb->dev = netdev_pub(wg);
|
|
+
|
|
+ rcu_read_lock();
|
|
+ sock = rcu_dereference(wg->sock4);
|
|
+
|
|
+ if (unlikely(!sock)) {
|
|
+ ret = -ENONET;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ if (cache)
|
|
+ rt = dst_cache_get_ip4(cache, &fl.saddr);
|
|
+
|
|
+ if (!rt) {
|
|
+ security_sk_classify_flow(sock, flowi4_to_flowi(&fl));
|
|
+ rt = ip_route_output_flow(sock_net(sock), &fl, sock);
|
|
+ if (unlikely(IS_ERR(rt) && PTR_ERR(rt) == -EINVAL && fl.saddr)) {
|
|
+ endpoint->src4.s_addr = fl.saddr = 0;
|
|
+ if (cache)
|
|
+ dst_cache_reset(cache);
|
|
+ rt = ip_route_output_flow(sock_net(sock), &fl, sock);
|
|
+ }
|
|
+ if (unlikely(IS_ERR(rt))) {
|
|
+ ret = PTR_ERR(rt);
|
|
+ net_dbg_ratelimited("No route to %pISpfsc, error %d\n", &endpoint->addr, ret);
|
|
+ goto err;
|
|
+ } else if (unlikely(rt->dst.dev == skb->dev)) {
|
|
+ dst_release(&rt->dst);
|
|
+ ret = -ELOOP;
|
|
+ net_dbg_ratelimited("Avoiding routing loop to %pISpfsc\n", &endpoint->addr);
|
|
+ goto err;
|
|
+ }
|
|
+ if (cache)
|
|
+ dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
|
|
+ }
|
|
+ udp_tunnel_xmit_skb(rt, sock, skb,
|
|
+ fl.saddr, fl.daddr,
|
|
+ ds, ip4_dst_hoplimit(&rt->dst), 0,
|
|
+ fl.fl4_sport, fl.fl4_dport,
|
|
+ false, false);
|
|
+ goto out;
|
|
+
|
|
+err:
|
|
+ kfree_skb(skb);
|
|
+out:
|
|
+ rcu_read_unlock();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static inline int send6(struct wireguard_device *wg, struct sk_buff *skb, struct endpoint *endpoint, u8 ds, struct dst_cache *cache)
|
|
+{
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ struct flowi6 fl = {
|
|
+ .saddr = endpoint->src6,
|
|
+ .daddr = endpoint->addr6.sin6_addr,
|
|
+ .fl6_dport = endpoint->addr6.sin6_port,
|
|
+ .fl6_sport = htons(wg->incoming_port),
|
|
+ .flowi6_mark = wg->fwmark,
|
|
+ .flowi6_oif = endpoint->addr6.sin6_scope_id,
|
|
+ .flowi6_proto = IPPROTO_UDP
|
|
+ /* TODO: addr->sin6_flowinfo */
|
|
+ };
|
|
+ struct dst_entry *dst = NULL;
|
|
+ struct sock *sock;
|
|
+ int ret = 0;
|
|
+
|
|
+ skb->next = skb->prev = NULL;
|
|
+ skb->dev = netdev_pub(wg);
|
|
+
|
|
+ rcu_read_lock();
|
|
+ sock = rcu_dereference(wg->sock6);
|
|
+
|
|
+ if (unlikely(!sock)) {
|
|
+ ret = -ENONET;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ if (cache)
|
|
+ dst = dst_cache_get_ip6(cache, &fl.saddr);
|
|
+
|
|
+ if (!dst) {
|
|
+ security_sk_classify_flow(sock, flowi6_to_flowi(&fl));
|
|
+ if (unlikely(!ipv6_addr_any(&fl.saddr) && !ipv6_chk_addr(sock_net(sock), &fl.saddr, NULL, 0))) {
|
|
+ endpoint->src6 = fl.saddr = in6addr_any;
|
|
+ if (cache)
|
|
+ dst_cache_reset(cache);
|
|
+ }
|
|
+ ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl);
|
|
+ if (unlikely(ret)) {
|
|
+ net_dbg_ratelimited("No route to %pISpfsc, error %d\n", &endpoint->addr, ret);
|
|
+ goto err;
|
|
+ } else if (unlikely(dst->dev == skb->dev)) {
|
|
+ dst_release(dst);
|
|
+ ret = -ELOOP;
|
|
+ net_dbg_ratelimited("Avoiding routing loop to %pISpfsc\n", &endpoint->addr);
|
|
+ goto err;
|
|
+ }
|
|
+ if (cache)
|
|
+ dst_cache_set_ip6(cache, dst, &fl.saddr);
|
|
+ }
|
|
+
|
|
+ udp_tunnel6_xmit_skb(dst, sock, skb, skb->dev,
|
|
+ &fl.saddr, &fl.daddr,
|
|
+ ds, ip6_dst_hoplimit(dst), 0,
|
|
+ fl.fl6_sport, fl.fl6_dport,
|
|
+ false);
|
|
+ goto out;
|
|
+
|
|
+err:
|
|
+ kfree_skb(skb);
|
|
+out:
|
|
+ rcu_read_unlock();
|
|
+ return ret;
|
|
+#else
|
|
+ return -EAFNOSUPPORT;
|
|
+#endif
|
|
+}
|
|
+
|
|
+int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 ds)
|
|
+{
|
|
+ size_t skb_len = skb->len;
|
|
+ int ret = -EAFNOSUPPORT;
|
|
+
|
|
+ read_lock_bh(&peer->endpoint_lock);
|
|
+ if (peer->endpoint.addr.sa_family == AF_INET)
|
|
+ ret = send4(peer->device, skb, &peer->endpoint, ds, &peer->endpoint_cache);
|
|
+ else if (peer->endpoint.addr.sa_family == AF_INET6)
|
|
+ ret = send6(peer->device, skb, &peer->endpoint, ds, &peer->endpoint_cache);
|
|
+ if (likely(!ret))
|
|
+ peer->tx_bytes += skb_len;
|
|
+ read_unlock_bh(&peer->endpoint_lock);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *buffer, size_t len, u8 ds)
|
|
+{
|
|
+ struct sk_buff *skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC);
|
|
+ if (unlikely(!skb))
|
|
+ return -ENOMEM;
|
|
+ skb_reserve(skb, SKB_HEADER_LEN);
|
|
+ memcpy(skb_put(skb, len), buffer, len);
|
|
+ return socket_send_skb_to_peer(peer, skb, ds);
|
|
+}
|
|
+
|
|
+int socket_send_buffer_as_reply_to_skb(struct wireguard_device *wg, struct sk_buff *in_skb, void *out_buffer, size_t len)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct sk_buff *skb;
|
|
+ struct endpoint endpoint;
|
|
+
|
|
+ if (unlikely(!in_skb))
|
|
+ return -EINVAL;
|
|
+ ret = socket_endpoint_from_skb(&endpoint, in_skb);
|
|
+ if (unlikely(ret < 0))
|
|
+ return ret;
|
|
+
|
|
+ skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC);
|
|
+ if (unlikely(!skb))
|
|
+ return -ENOMEM;
|
|
+ skb_reserve(skb, SKB_HEADER_LEN);
|
|
+ memcpy(skb_put(skb, len), out_buffer, len);
|
|
+
|
|
+ if (endpoint.addr.sa_family == AF_INET)
|
|
+ ret = send4(wg, skb, &endpoint, 0, NULL);
|
|
+ else if (endpoint.addr.sa_family == AF_INET6)
|
|
+ ret = send6(wg, skb, &endpoint, 0, NULL);
|
|
+ else
|
|
+ ret = -EAFNOSUPPORT;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int socket_endpoint_from_skb(struct endpoint *endpoint, struct sk_buff *skb)
|
|
+{
|
|
+ memset(endpoint, 0, sizeof(struct endpoint));
|
|
+ if (ip_hdr(skb)->version == 4) {
|
|
+ endpoint->addr4.sin_family = AF_INET;
|
|
+ endpoint->addr4.sin_port = udp_hdr(skb)->source;
|
|
+ endpoint->addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
|
|
+ endpoint->src4.s_addr = ip_hdr(skb)->daddr;
|
|
+ } else if (ip_hdr(skb)->version == 6) {
|
|
+ endpoint->addr6.sin6_family = AF_INET6;
|
|
+ endpoint->addr6.sin6_port = udp_hdr(skb)->source;
|
|
+ endpoint->addr6.sin6_addr = ipv6_hdr(skb)->saddr;
|
|
+ endpoint->addr6.sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr, skb->skb_iif);
|
|
+ /* TODO: endpoint->addr6.sin6_flowinfo */
|
|
+ endpoint->src6 = ipv6_hdr(skb)->daddr;
|
|
+ } else
|
|
+ return -EINVAL;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void socket_set_peer_endpoint(struct wireguard_peer *peer, struct endpoint *endpoint)
|
|
+{
|
|
+ if (endpoint->addr.sa_family == AF_INET) {
|
|
+ read_lock_bh(&peer->endpoint_lock);
|
|
+ if (likely(peer->endpoint.addr4.sin_family == AF_INET &&
|
|
+ peer->endpoint.addr4.sin_port == endpoint->addr4.sin_port &&
|
|
+ peer->endpoint.addr4.sin_addr.s_addr == endpoint->addr4.sin_addr.s_addr &&
|
|
+ peer->endpoint.src4.s_addr == endpoint->src4.s_addr))
|
|
+ goto out;
|
|
+ read_unlock_bh(&peer->endpoint_lock);
|
|
+ write_lock_bh(&peer->endpoint_lock);
|
|
+ peer->endpoint.addr4 = endpoint->addr4;
|
|
+ peer->endpoint.src4 = endpoint->src4;
|
|
+ } else if (endpoint->addr.sa_family == AF_INET6) {
|
|
+ read_lock_bh(&peer->endpoint_lock);
|
|
+ if (likely(peer->endpoint.addr6.sin6_family == AF_INET6 &&
|
|
+ peer->endpoint.addr6.sin6_port == endpoint->addr6.sin6_port &&
|
|
+ /* TODO: peer->endpoint.addr6.sin6_flowinfo == endpoint->addr6.sin6_flowinfo && */
|
|
+ ipv6_addr_equal(&peer->endpoint.addr6.sin6_addr, &endpoint->addr6.sin6_addr) &&
|
|
+ peer->endpoint.addr6.sin6_scope_id == endpoint->addr6.sin6_scope_id &&
|
|
+ ipv6_addr_equal(&peer->endpoint.src6, &endpoint->src6)))
|
|
+ goto out;
|
|
+ read_unlock_bh(&peer->endpoint_lock);
|
|
+ write_lock_bh(&peer->endpoint_lock);
|
|
+ peer->endpoint.addr6 = endpoint->addr6;
|
|
+ peer->endpoint.src6 = endpoint->src6;
|
|
+ } else
|
|
+ return;
|
|
+ dst_cache_reset(&peer->endpoint_cache);
|
|
+ write_unlock_bh(&peer->endpoint_lock);
|
|
+ return;
|
|
+out:
|
|
+ read_unlock_bh(&peer->endpoint_lock);
|
|
+}
|
|
+
|
|
+void socket_clear_peer_endpoint_src(struct wireguard_peer *peer)
|
|
+{
|
|
+ write_lock_bh(&peer->endpoint_lock);
|
|
+ memset(&peer->endpoint.src6, 0, sizeof(peer->endpoint.src6));
|
|
+ dst_cache_reset(&peer->endpoint_cache);
|
|
+ write_unlock_bh(&peer->endpoint_lock);
|
|
+}
|
|
+
|
|
+static int receive(struct sock *sk, struct sk_buff *skb)
|
|
+{
|
|
+ struct wireguard_device *wg;
|
|
+
|
|
+ if (unlikely(!sk))
|
|
+ goto err;
|
|
+ wg = sk->sk_user_data;
|
|
+ if (unlikely(!wg))
|
|
+ goto err;
|
|
+ packet_receive(wg, skb);
|
|
+ return 0;
|
|
+
|
|
+err:
|
|
+ kfree_skb(skb);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void sock_free(struct sock *sock)
|
|
+{
|
|
+ if (unlikely(!sock))
|
|
+ return;
|
|
+ sk_clear_memalloc(sock);
|
|
+ udp_tunnel_sock_release(sock->sk_socket);
|
|
+}
|
|
+
|
|
+static inline void set_sock_opts(struct socket *sock)
|
|
+{
|
|
+ sock->sk->sk_allocation = GFP_ATOMIC;
|
|
+ sock->sk->sk_sndbuf = INT_MAX;
|
|
+ sk_set_memalloc(sock->sk);
|
|
+}
|
|
+
|
|
+int socket_init(struct wireguard_device *wg)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct udp_tunnel_sock_cfg cfg = {
|
|
+ .sk_user_data = wg,
|
|
+ .encap_type = 1,
|
|
+ .encap_rcv = receive
|
|
+ };
|
|
+ struct socket *new4 = NULL;
|
|
+ struct udp_port_cfg port4 = {
|
|
+ .family = AF_INET,
|
|
+ .local_ip.s_addr = htonl(INADDR_ANY),
|
|
+ .local_udp_port = htons(wg->incoming_port),
|
|
+ .use_udp_checksums = true
|
|
+ };
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ int retries = 0;
|
|
+ struct socket *new6 = NULL;
|
|
+ struct udp_port_cfg port6 = {
|
|
+ .family = AF_INET6,
|
|
+ .local_ip6 = IN6ADDR_ANY_INIT,
|
|
+ .local_udp_port = htons(wg->incoming_port),
|
|
+ .use_udp6_tx_checksums = true,
|
|
+ .use_udp6_rx_checksums = true,
|
|
+ .ipv6_v6only = true
|
|
+ };
|
|
+retry:
|
|
+#endif
|
|
+
|
|
+ mutex_lock(&wg->socket_update_lock);
|
|
+
|
|
+ if (rcu_dereference_protected(wg->sock4, lockdep_is_held(&wg->socket_update_lock)) ||
|
|
+ rcu_dereference_protected(wg->sock6, lockdep_is_held(&wg->socket_update_lock))) {
|
|
+ ret = -EADDRINUSE;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = udp_sock_create(wg->creating_net, &port4, &new4);
|
|
+ if (ret < 0) {
|
|
+ pr_err("Could not create IPv4 socket\n");
|
|
+ goto out;
|
|
+ }
|
|
+ wg->incoming_port = ntohs(inet_sk(new4->sk)->inet_sport);
|
|
+
|
|
+ set_sock_opts(new4);
|
|
+ setup_udp_tunnel_sock(wg->creating_net, new4, &cfg);
|
|
+ rcu_assign_pointer(wg->sock4, new4->sk);
|
|
+
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ if (!ipv6_mod_enabled())
|
|
+ goto out;
|
|
+ port6.local_udp_port = htons(wg->incoming_port);
|
|
+ ret = udp_sock_create(wg->creating_net, &port6, &new6);
|
|
+ if (ret < 0) {
|
|
+ udp_tunnel_sock_release(new4);
|
|
+ rcu_assign_pointer(wg->sock4, NULL);
|
|
+ if (ret == -EADDRINUSE && !port4.local_udp_port && retries++ < 100)
|
|
+ goto retry;
|
|
+ if (!port4.local_udp_port)
|
|
+ wg->incoming_port = 0;
|
|
+ pr_err("Could not create IPv6 socket\n");
|
|
+ goto out;
|
|
+ }
|
|
+ set_sock_opts(new6);
|
|
+ setup_udp_tunnel_sock(wg->creating_net, new6, &cfg);
|
|
+ rcu_assign_pointer(wg->sock6, new6->sk);
|
|
+#endif
|
|
+
|
|
+out:
|
|
+ mutex_unlock(&wg->socket_update_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void socket_uninit(struct wireguard_device *wg)
|
|
+{
|
|
+ struct sock *old4, *old6;
|
|
+ mutex_lock(&wg->socket_update_lock);
|
|
+ old4 = rcu_dereference_protected(wg->sock4, lockdep_is_held(&wg->socket_update_lock));
|
|
+ old6 = rcu_dereference_protected(wg->sock6, lockdep_is_held(&wg->socket_update_lock));
|
|
+ rcu_assign_pointer(wg->sock4, NULL);
|
|
+ rcu_assign_pointer(wg->sock6, NULL);
|
|
+ mutex_unlock(&wg->socket_update_lock);
|
|
+ synchronize_rcu();
|
|
+ synchronize_net();
|
|
+ sock_free(old4);
|
|
+ sock_free(old6);
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/timers.c
|
|
@@ -0,0 +1,178 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#include "timers.h"
|
|
+#include "device.h"
|
|
+#include "peer.h"
|
|
+#include "packets.h"
|
|
+
|
|
+/*
|
|
+ * Timer for retransmitting the handshake if we don't hear back after `REKEY_TIMEOUT` ms
|
|
+ * Timer for sending empty packet if we have received a packet but after have not sent one for `KEEPALIVE_TIMEOUT` ms
|
|
+ * Timer for initiating new handshake if we have sent a packet but after have not received one (even empty) for `(KEEPALIVE_TIMEOUT + REKEY_TIMEOUT)` ms
|
|
+ * Timer for zeroing out all ephemeral keys after `(REJECT_AFTER_TIME * 3)` ms if no new keys have been received
|
|
+ * Timer for, if enabled, sending an empty authenticated packet every user-specified seconds
|
|
+ */
|
|
+
|
|
+/* This rounds the time down to the closest power of two of the closest quarter second. */
|
|
+static inline unsigned long slack_time(unsigned long time)
|
|
+{
|
|
+ return time & ~(roundup_pow_of_two(HZ / 4) - 1);
|
|
+}
|
|
+
|
|
+#define peer_get_from_ptr(ptr) \
|
|
+ struct wireguard_peer *peer = peer_rcu_get((struct wireguard_peer *)ptr); \
|
|
+ if (unlikely(!peer)) \
|
|
+ return;
|
|
+
|
|
+static void expired_retransmit_handshake(unsigned long ptr)
|
|
+{
|
|
+ peer_get_from_ptr(ptr);
|
|
+ pr_debug("Handshake for peer %Lu (%pISpfsc) did not complete after %d seconds, retrying\n", peer->internal_id, &peer->endpoint.addr, REKEY_TIMEOUT / HZ);
|
|
+ if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES) {
|
|
+ del_timer(&peer->timer_send_keepalive);
|
|
+ /* We remove all existing packets and don't try again,
|
|
+ * if we try unsuccessfully for too long to make a handshake. */
|
|
+ skb_queue_purge(&peer->tx_packet_queue);
|
|
+ /* We set a timer for destroying any residue that might be left
|
|
+ * of a partial exchange. */
|
|
+ if (likely(peer->timers_enabled))
|
|
+ mod_timer(&peer->timer_kill_ephemerals, jiffies + (REJECT_AFTER_TIME * 3));
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /* We clear the endpoint address src address, in case this is the cause of trouble. */
|
|
+ socket_clear_peer_endpoint_src(peer);
|
|
+
|
|
+ packet_queue_handshake_initiation(peer);
|
|
+ ++peer->timer_handshake_attempts;
|
|
+out:
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+static void expired_send_keepalive(unsigned long ptr)
|
|
+{
|
|
+ peer_get_from_ptr(ptr);
|
|
+ packet_send_keepalive(peer);
|
|
+ if (peer->timer_need_another_keepalive) {
|
|
+ peer->timer_need_another_keepalive = false;
|
|
+ if (peer->timers_enabled)
|
|
+ mod_timer(&peer->timer_send_keepalive, jiffies + KEEPALIVE_TIMEOUT);
|
|
+ }
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+static void expired_new_handshake(unsigned long ptr)
|
|
+{
|
|
+ peer_get_from_ptr(ptr);
|
|
+ pr_debug("Retrying handshake with peer %Lu (%pISpfsc) because we stopped hearing back after %d seconds\n", peer->internal_id, &peer->endpoint.addr, (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) / HZ);
|
|
+ /* We clear the endpoint address src address, in case this is the cause of trouble. */
|
|
+ socket_clear_peer_endpoint_src(peer);
|
|
+ packet_queue_handshake_initiation(peer);
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+static void expired_kill_ephemerals(unsigned long ptr)
|
|
+{
|
|
+ peer_get_from_ptr(ptr);
|
|
+ if (!queue_work(peer->device->workqueue, &peer->clear_peer_work)) /* Takes our reference. */
|
|
+ peer_put(peer); /* If the work was already on the queue, we want to drop the extra reference */
|
|
+}
|
|
+static void queued_expired_kill_ephemerals(struct work_struct *work)
|
|
+{
|
|
+ struct wireguard_peer *peer = container_of(work, struct wireguard_peer, clear_peer_work);
|
|
+ pr_debug("Zeroing out all keys for peer %Lu (%pISpfsc), since we haven't received a new one in %d seconds\n", peer->internal_id, &peer->endpoint.addr, (REJECT_AFTER_TIME * 3) / HZ);
|
|
+ noise_handshake_clear(&peer->handshake);
|
|
+ noise_keypairs_clear(&peer->keypairs);
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+static void expired_send_persistent_keepalive(unsigned long ptr)
|
|
+{
|
|
+ peer_get_from_ptr(ptr);
|
|
+ if (likely(peer->persistent_keepalive_interval))
|
|
+ packet_send_keepalive(peer);
|
|
+ peer_put(peer);
|
|
+}
|
|
+
|
|
+/* Should be called after an authenticated data packet is sent. */
|
|
+void timers_data_sent(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (likely(peer->timers_enabled))
|
|
+ del_timer(&peer->timer_send_keepalive);
|
|
+
|
|
+ if (likely(peer->timers_enabled) && !timer_pending(&peer->timer_new_handshake))
|
|
+ mod_timer(&peer->timer_new_handshake, jiffies + KEEPALIVE_TIMEOUT + REKEY_TIMEOUT);
|
|
+}
|
|
+
|
|
+/* Should be called after an authenticated data packet is received. */
|
|
+void timers_data_received(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (likely(peer->timers_enabled) && !timer_pending(&peer->timer_send_keepalive))
|
|
+ mod_timer(&peer->timer_send_keepalive, jiffies + KEEPALIVE_TIMEOUT);
|
|
+ else
|
|
+ peer->timer_need_another_keepalive = true;
|
|
+}
|
|
+
|
|
+/* Should be called after any type of authenticated packet is received -- keepalive or data. */
|
|
+void timers_any_authenticated_packet_received(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (likely(peer->timers_enabled))
|
|
+ del_timer(&peer->timer_new_handshake);
|
|
+}
|
|
+
|
|
+/* Should be called after a handshake initiation message is sent. */
|
|
+void timers_handshake_initiated(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (likely(peer->timers_enabled))
|
|
+ del_timer(&peer->timer_send_keepalive);
|
|
+ if (likely(peer->timers_enabled))
|
|
+ mod_timer(&peer->timer_retransmit_handshake, slack_time(jiffies + REKEY_TIMEOUT + prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX)));
|
|
+}
|
|
+
|
|
+/* Should be called after a handshake response message is received and processed. */
|
|
+void timers_handshake_complete(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (likely(peer->timers_enabled))
|
|
+ del_timer(&peer->timer_retransmit_handshake);
|
|
+ peer->timer_handshake_attempts = 0;
|
|
+}
|
|
+
|
|
+/* Should be called after an ephemeral key is created, which is before sending a handshake response or after receiving a handshake response. */
|
|
+void timers_ephemeral_key_created(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (likely(peer->timers_enabled))
|
|
+ mod_timer(&peer->timer_kill_ephemerals, jiffies + (REJECT_AFTER_TIME * 3));
|
|
+ do_gettimeofday(&peer->walltime_last_handshake);
|
|
+}
|
|
+
|
|
+/* Should be called before an packet with authentication -- data, keepalive, either handshake -- is sent, or after one is received. */
|
|
+void timers_any_authenticated_packet_traversal(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (peer->persistent_keepalive_interval && likely(peer->timers_enabled))
|
|
+ mod_timer(&peer->timer_persistent_keepalive, slack_time(jiffies + peer->persistent_keepalive_interval));
|
|
+}
|
|
+
|
|
+void timers_init_peer(struct wireguard_peer *peer)
|
|
+{
|
|
+ peer->timers_enabled = true;
|
|
+ setup_timer(&peer->timer_retransmit_handshake, expired_retransmit_handshake, (unsigned long)peer);
|
|
+ setup_timer(&peer->timer_send_keepalive, expired_send_keepalive, (unsigned long)peer);
|
|
+ setup_timer(&peer->timer_new_handshake, expired_new_handshake, (unsigned long)peer);
|
|
+ setup_timer(&peer->timer_kill_ephemerals, expired_kill_ephemerals, (unsigned long)peer);
|
|
+ setup_timer(&peer->timer_persistent_keepalive, expired_send_persistent_keepalive, (unsigned long)peer);
|
|
+ INIT_WORK(&peer->clear_peer_work, queued_expired_kill_ephemerals);
|
|
+}
|
|
+
|
|
+void timers_uninit_peer(struct wireguard_peer *peer)
|
|
+{
|
|
+ if (!peer->timers_enabled)
|
|
+ return;
|
|
+ peer->timers_enabled = false;
|
|
+ wmb();
|
|
+ del_timer_sync(&peer->timer_retransmit_handshake);
|
|
+ del_timer_sync(&peer->timer_send_keepalive);
|
|
+ del_timer_sync(&peer->timer_new_handshake);
|
|
+ del_timer_sync(&peer->timer_kill_ephemerals);
|
|
+ del_timer_sync(&peer->timer_persistent_keepalive);
|
|
+ flush_work(&peer->clear_peer_work);
|
|
+}
|
|
--- /dev/null
|
|
+++ b/net/wireguard/config.h
|
|
@@ -0,0 +1,11 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef WGCONFIG_H
|
|
+#define WGCONFIG_H
|
|
+
|
|
+struct wireguard_device;
|
|
+
|
|
+int config_get_device(struct wireguard_device *wg, void __user *udevice);
|
|
+int config_set_device(struct wireguard_device *wg, void __user *udevice);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/cookie.h
|
|
@@ -0,0 +1,51 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef WGCOOKIE_H
|
|
+#define WGCOOKIE_H
|
|
+
|
|
+#include "messages.h"
|
|
+#include "ratelimiter.h"
|
|
+#include <linux/rwsem.h>
|
|
+
|
|
+struct wireguard_peer;
|
|
+struct wireguard_device;
|
|
+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;
|
|
+ struct wireguard_device *device;
|
|
+};
|
|
+
|
|
+struct cookie {
|
|
+ u64 birthdate;
|
|
+ bool is_valid;
|
|
+ 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;
|
|
+};
|
|
+
|
|
+enum cookie_mac_state {
|
|
+ INVALID_MAC,
|
|
+ VALID_MAC_BUT_NO_COOKIE,
|
|
+ VALID_MAC_WITH_COOKIE_BUT_RATELIMITED,
|
|
+ VALID_MAC_WITH_COOKIE
|
|
+};
|
|
+
|
|
+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);
|
|
+void cookie_add_mac_to_packet(void *message, size_t len, struct wireguard_peer *peer);
|
|
+
|
|
+void cookie_message_create(struct message_handshake_cookie *src, struct sk_buff *skb, void *data_start, size_t data_len, __le32 index, struct cookie_checker *checker);
|
|
+void cookie_message_consume(struct message_handshake_cookie *src, struct wireguard_device *wg);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/device.h
|
|
@@ -0,0 +1,45 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef WGDEVICE_H
|
|
+#define WGDEVICE_H
|
|
+
|
|
+#include "noise.h"
|
|
+#include "routingtable.h"
|
|
+#include "hashtables.h"
|
|
+#include "cookie.h"
|
|
+
|
|
+#include <linux/types.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/net.h>
|
|
+#include <linux/padata.h>
|
|
+#include <linux/notifier.h>
|
|
+
|
|
+struct wireguard_device {
|
|
+ struct sock __rcu *sock4, *sock6;
|
|
+ u16 incoming_port;
|
|
+ u32 fwmark;
|
|
+ struct net *creating_net;
|
|
+ struct workqueue_struct *workqueue;
|
|
+ struct workqueue_struct *parallelqueue;
|
|
+ struct padata_instance *parallel_send, *parallel_receive;
|
|
+ struct noise_static_identity static_identity;
|
|
+ struct sk_buff_head incoming_handshakes;
|
|
+ struct work_struct incoming_handshakes_work;
|
|
+ struct cookie_checker cookie_checker;
|
|
+ struct pubkey_hashtable peer_hashtable;
|
|
+ struct index_hashtable index_hashtable;
|
|
+ struct routing_table peer_routing_table;
|
|
+ struct list_head peer_list;
|
|
+ struct mutex device_update_lock;
|
|
+ struct mutex socket_update_lock;
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
+ struct notifier_block clear_peers_on_suspend;
|
|
+#endif
|
|
+};
|
|
+
|
|
+int device_init(void);
|
|
+void device_uninit(void);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/hashtables.h
|
|
@@ -0,0 +1,48 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef HASHTABLES_H
|
|
+#define HASHTABLES_H
|
|
+
|
|
+#include "messages.h"
|
|
+
|
|
+#include <linux/hashtable.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/siphash.h>
|
|
+
|
|
+struct wireguard_peer;
|
|
+
|
|
+struct pubkey_hashtable {
|
|
+ DECLARE_HASHTABLE(hashtable, 8);
|
|
+ siphash_key_t key;
|
|
+ struct mutex lock;
|
|
+};
|
|
+
|
|
+void pubkey_hashtable_init(struct pubkey_hashtable *table);
|
|
+void pubkey_hashtable_add(struct pubkey_hashtable *table, struct wireguard_peer *peer);
|
|
+void pubkey_hashtable_remove(struct pubkey_hashtable *table, struct wireguard_peer *peer);
|
|
+struct wireguard_peer *pubkey_hashtable_lookup(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN]);
|
|
+
|
|
+struct index_hashtable {
|
|
+ DECLARE_HASHTABLE(hashtable, 10);
|
|
+ siphash_key_t key;
|
|
+ spinlock_t lock;
|
|
+};
|
|
+
|
|
+enum index_hashtable_type {
|
|
+ INDEX_HASHTABLE_HANDSHAKE = (1 << 0),
|
|
+ INDEX_HASHTABLE_KEYPAIR = (1 << 1)
|
|
+};
|
|
+
|
|
+struct index_hashtable_entry {
|
|
+ struct wireguard_peer *peer;
|
|
+ struct hlist_node index_hash;
|
|
+ enum index_hashtable_type type;
|
|
+ __le32 index;
|
|
+};
|
|
+void index_hashtable_init(struct index_hashtable *table);
|
|
+__le32 index_hashtable_insert(struct index_hashtable *table, struct index_hashtable_entry *entry);
|
|
+void index_hashtable_replace(struct index_hashtable *table, struct index_hashtable_entry *old, struct index_hashtable_entry *new);
|
|
+void index_hashtable_remove(struct index_hashtable *table, struct index_hashtable_entry *entry);
|
|
+struct index_hashtable_entry *index_hashtable_lookup(struct index_hashtable *table, const enum index_hashtable_type type_mask, const __le32 index);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/messages.h
|
|
@@ -0,0 +1,143 @@
|
|
+/*
|
|
+ * Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ *
|
|
+ * See doc/protocol.md for more info
|
|
+ */
|
|
+
|
|
+#ifndef MESSAGES_H
|
|
+#define MESSAGES_H
|
|
+
|
|
+#include "crypto/curve25519.h"
|
|
+#include "crypto/chacha20poly1305.h"
|
|
+#include "crypto/blake2s.h"
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/param.h>
|
|
+
|
|
+enum noise_lengths {
|
|
+ NOISE_PUBLIC_KEY_LEN = CURVE25519_POINT_SIZE,
|
|
+ NOISE_SYMMETRIC_KEY_LEN = CHACHA20POLY1305_KEYLEN,
|
|
+ NOISE_TIMESTAMP_LEN = sizeof(u64) + sizeof(u32),
|
|
+ NOISE_AUTHTAG_LEN = CHACHA20POLY1305_AUTHTAGLEN,
|
|
+ NOISE_HASH_LEN = BLAKE2S_OUTBYTES
|
|
+};
|
|
+
|
|
+#define noise_encrypted_len(plain_len) (plain_len + NOISE_AUTHTAG_LEN)
|
|
+
|
|
+enum cookie_values {
|
|
+ COOKIE_SECRET_MAX_AGE = 2 * 60 * HZ,
|
|
+ COOKIE_SECRET_LATENCY = 5 * HZ,
|
|
+ COOKIE_NONCE_LEN = XCHACHA20POLY1305_NONCELEN,
|
|
+ COOKIE_LEN = 16
|
|
+};
|
|
+
|
|
+enum counter_values {
|
|
+ COUNTER_BITS_TOTAL = 2048,
|
|
+ COUNTER_REDUNDANT_BITS = BITS_PER_LONG,
|
|
+ COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS
|
|
+};
|
|
+
|
|
+enum limits {
|
|
+ REKEY_AFTER_MESSAGES = U64_MAX - 0xffff,
|
|
+ REJECT_AFTER_MESSAGES = U64_MAX - COUNTER_WINDOW_SIZE - 1,
|
|
+ REKEY_TIMEOUT = 5 * HZ,
|
|
+ REKEY_TIMEOUT_JITTER_MAX = HZ / 3,
|
|
+ REKEY_AFTER_TIME = 120 * HZ,
|
|
+ REJECT_AFTER_TIME = 180 * HZ,
|
|
+ INITIATIONS_PER_SECOND = HZ / 50,
|
|
+ MAX_PEERS_PER_DEVICE = U16_MAX,
|
|
+ KEEPALIVE_TIMEOUT = 10 * HZ,
|
|
+ MAX_TIMER_HANDSHAKES = (90 * HZ) / REKEY_TIMEOUT,
|
|
+ MAX_QUEUED_INCOMING_HANDSHAKES = 4096,
|
|
+ MAX_BURST_INCOMING_HANDSHAKES = 16,
|
|
+ MAX_QUEUED_OUTGOING_PACKETS = 1024
|
|
+};
|
|
+
|
|
+enum message_type {
|
|
+ MESSAGE_INVALID = 0,
|
|
+ MESSAGE_HANDSHAKE_INITIATION = 1,
|
|
+ MESSAGE_HANDSHAKE_RESPONSE = 2,
|
|
+ MESSAGE_HANDSHAKE_COOKIE = 3,
|
|
+ MESSAGE_DATA = 4,
|
|
+ MESSAGE_TOTAL = 5
|
|
+};
|
|
+
|
|
+struct message_header {
|
|
+ /* The actual layout of this that we want is:
|
|
+ * u8 type
|
|
+ * u8 reserved_zero[3]
|
|
+ *
|
|
+ * But it turns out that by encoding this as little endian,
|
|
+ * we achieve the same thing, and it makes checking faster.
|
|
+ */
|
|
+ __le32 type;
|
|
+};
|
|
+
|
|
+struct message_macs {
|
|
+ u8 mac1[COOKIE_LEN];
|
|
+ u8 mac2[COOKIE_LEN];
|
|
+};
|
|
+
|
|
+struct message_handshake_initiation {
|
|
+ struct message_header header;
|
|
+ __le32 sender_index;
|
|
+ u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 encrypted_static[noise_encrypted_len(NOISE_PUBLIC_KEY_LEN)];
|
|
+ u8 encrypted_timestamp[noise_encrypted_len(NOISE_TIMESTAMP_LEN)];
|
|
+ struct message_macs macs;
|
|
+};
|
|
+
|
|
+struct message_handshake_response {
|
|
+ struct message_header header;
|
|
+ __le32 sender_index;
|
|
+ __le32 receiver_index;
|
|
+ u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 encrypted_nothing[noise_encrypted_len(0)];
|
|
+ struct message_macs macs;
|
|
+};
|
|
+
|
|
+struct message_handshake_cookie {
|
|
+ struct message_header header;
|
|
+ __le32 receiver_index;
|
|
+ u8 nonce[COOKIE_NONCE_LEN];
|
|
+ u8 encrypted_cookie[noise_encrypted_len(COOKIE_LEN)];
|
|
+};
|
|
+
|
|
+struct message_data {
|
|
+ struct message_header header;
|
|
+ __le32 key_idx;
|
|
+ __le64 counter;
|
|
+ u8 encrypted_data[];
|
|
+};
|
|
+
|
|
+#define message_data_len(plain_len) (noise_encrypted_len(plain_len) + sizeof(struct message_data))
|
|
+
|
|
+enum message_alignments {
|
|
+ MESSAGE_PADDING_MULTIPLE = 16,
|
|
+ MESSAGE_MINIMUM_LENGTH = message_data_len(0)
|
|
+};
|
|
+
|
|
+#define SKB_HEADER_LEN (max(sizeof(struct iphdr), sizeof(struct ipv6hdr)) + sizeof(struct udphdr) + NET_SKB_PAD)
|
|
+#define DATA_PACKET_HEAD_ROOM ALIGN(sizeof(struct message_data) + SKB_HEADER_LEN, 4)
|
|
+
|
|
+enum {
|
|
+ HANDSHAKE_DSCP = 0b10001000 /* AF41, plus 00 ECN */
|
|
+};
|
|
+
|
|
+static inline enum message_type message_determine_type(void *src, size_t src_len)
|
|
+{
|
|
+ struct message_header *header = src;
|
|
+ if (unlikely(src_len < sizeof(struct message_header)))
|
|
+ return MESSAGE_INVALID;
|
|
+ if (header->type == cpu_to_le32(MESSAGE_DATA) && src_len >= MESSAGE_MINIMUM_LENGTH)
|
|
+ return MESSAGE_DATA;
|
|
+ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION) && src_len == sizeof(struct message_handshake_initiation))
|
|
+ return MESSAGE_HANDSHAKE_INITIATION;
|
|
+ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE) && src_len == sizeof(struct message_handshake_response))
|
|
+ return MESSAGE_HANDSHAKE_RESPONSE;
|
|
+ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE) && src_len == sizeof(struct message_handshake_cookie))
|
|
+ return MESSAGE_HANDSHAKE_COOKIE;
|
|
+ return MESSAGE_INVALID;
|
|
+}
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/noise.h
|
|
@@ -0,0 +1,123 @@
|
|
+/*
|
|
+ * Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ *
|
|
+ * See doc/protocol.md and https://github.com/trevp/noise/blob/master/noise.md for more info
|
|
+ */
|
|
+
|
|
+#ifndef NOISE_H
|
|
+#define NOISE_H
|
|
+
|
|
+#include "messages.h"
|
|
+#include "hashtables.h"
|
|
+
|
|
+#include <linux/types.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/atomic.h>
|
|
+#include <linux/rwsem.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/jiffies.h>
|
|
+#include <linux/kref.h>
|
|
+
|
|
+union noise_counter {
|
|
+ struct {
|
|
+ u64 counter;
|
|
+ unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG];
|
|
+ spinlock_t lock;
|
|
+ } receive;
|
|
+ atomic64_t counter;
|
|
+};
|
|
+
|
|
+struct noise_symmetric_key {
|
|
+ u8 key[NOISE_SYMMETRIC_KEY_LEN];
|
|
+ union noise_counter counter;
|
|
+ u64 birthdate;
|
|
+ bool is_valid;
|
|
+};
|
|
+
|
|
+struct noise_keypair {
|
|
+ struct index_hashtable_entry entry;
|
|
+ struct noise_symmetric_key sending;
|
|
+ struct noise_symmetric_key receiving;
|
|
+ __le32 remote_index;
|
|
+ bool i_am_the_initiator;
|
|
+ struct kref refcount;
|
|
+ struct rcu_head rcu;
|
|
+ u64 internal_id;
|
|
+};
|
|
+
|
|
+struct noise_keypairs {
|
|
+ struct noise_keypair __rcu *current_keypair;
|
|
+ struct noise_keypair __rcu *previous_keypair;
|
|
+ struct noise_keypair __rcu *next_keypair;
|
|
+ struct mutex keypair_update_lock;
|
|
+};
|
|
+
|
|
+struct noise_static_identity {
|
|
+ bool has_identity, has_psk;
|
|
+ u8 static_public[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 static_private[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN];
|
|
+ struct rw_semaphore lock;
|
|
+};
|
|
+
|
|
+enum noise_handshake_state {
|
|
+ HANDSHAKE_ZEROED,
|
|
+ HANDSHAKE_CREATED_INITIATION,
|
|
+ HANDSHAKE_CONSUMED_INITIATION,
|
|
+ HANDSHAKE_CREATED_RESPONSE,
|
|
+ HANDSHAKE_CONSUMED_RESPONSE
|
|
+};
|
|
+
|
|
+struct noise_handshake {
|
|
+ struct index_hashtable_entry entry;
|
|
+
|
|
+ enum noise_handshake_state state;
|
|
+ u64 last_initiation_consumption;
|
|
+
|
|
+ struct noise_static_identity *static_identity;
|
|
+
|
|
+ u8 ephemeral_public[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN];
|
|
+
|
|
+ u8 remote_static[NOISE_PUBLIC_KEY_LEN];
|
|
+ u8 remote_ephemeral[NOISE_PUBLIC_KEY_LEN];
|
|
+
|
|
+ u8 key[NOISE_SYMMETRIC_KEY_LEN];
|
|
+ u8 hash[NOISE_HASH_LEN];
|
|
+ u8 chaining_key[NOISE_HASH_LEN];
|
|
+
|
|
+ u8 latest_timestamp[NOISE_TIMESTAMP_LEN];
|
|
+ __le32 remote_index;
|
|
+
|
|
+ /* Protects all members except the immutable (after noise_peer_init): remote_static, static_identity */
|
|
+ struct rw_semaphore lock;
|
|
+};
|
|
+
|
|
+struct wireguard_peer;
|
|
+struct wireguard_device;
|
|
+struct message_header;
|
|
+struct message_handshake_initiation;
|
|
+struct message_handshake_response;
|
|
+struct message_data;
|
|
+struct message_handshake_cookie;
|
|
+
|
|
+void noise_init(void);
|
|
+void noise_handshake_init(struct noise_handshake *handshake, struct noise_static_identity *static_identity, const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], struct wireguard_peer *peer);
|
|
+void noise_handshake_clear(struct noise_handshake *handshake);
|
|
+void noise_keypair_put(struct noise_keypair *keypair);
|
|
+struct noise_keypair *noise_keypair_get(struct noise_keypair *keypair);
|
|
+void noise_keypairs_clear(struct noise_keypairs *keypairs);
|
|
+bool noise_received_with_keypair(struct noise_keypairs *keypairs, struct noise_keypair *received_keypair);
|
|
+
|
|
+void noise_set_static_identity_private_key(struct noise_static_identity *static_identity, const u8 private_key[NOISE_PUBLIC_KEY_LEN]);
|
|
+void noise_set_static_identity_preshared_key(struct noise_static_identity *static_identity, const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]);
|
|
+
|
|
+bool noise_handshake_create_initiation(struct message_handshake_initiation *dst, struct noise_handshake *handshake);
|
|
+struct wireguard_peer *noise_handshake_consume_initiation(struct message_handshake_initiation *src, struct wireguard_device *wg);
|
|
+
|
|
+bool noise_handshake_create_response(struct message_handshake_response *dst, struct noise_handshake *peer);
|
|
+struct wireguard_peer *noise_handshake_consume_response(struct message_handshake_response *src, struct wireguard_device *wg);
|
|
+
|
|
+bool noise_handshake_begin_session(struct noise_handshake *handshake, struct noise_keypairs *keypairs, bool i_am_the_initiator);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/packets.h
|
|
@@ -0,0 +1,44 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef PACKETS_H
|
|
+#define PACKETS_H
|
|
+
|
|
+#include "noise.h"
|
|
+#include "messages.h"
|
|
+#include "socket.h"
|
|
+
|
|
+#include <linux/types.h>
|
|
+#include <linux/padata.h>
|
|
+
|
|
+struct wireguard_device;
|
|
+struct wireguard_peer;
|
|
+struct sk_buff;
|
|
+
|
|
+/* receive.c */
|
|
+void packet_receive(struct wireguard_device *wg, struct sk_buff *skb);
|
|
+void packet_process_queued_handshake_packets(struct work_struct *work);
|
|
+
|
|
+/* send.c */
|
|
+void packet_send_queue(struct wireguard_peer *peer);
|
|
+void packet_send_keepalive(struct wireguard_peer *peer);
|
|
+void packet_queue_handshake_initiation(struct wireguard_peer *peer);
|
|
+void packet_send_queued_handshakes(struct work_struct *work);
|
|
+void packet_send_handshake_response(struct wireguard_peer *peer);
|
|
+void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *initiating_skb, void *data, size_t data_len, __le32 sender_index);
|
|
+
|
|
+/* data.c */
|
|
+typedef void (*packet_create_data_callback_t)(struct sk_buff_head *, struct wireguard_peer *);
|
|
+typedef void (*packet_consume_data_callback_t)(struct sk_buff *skb, struct wireguard_peer *, struct endpoint *, bool used_new_key, int err);
|
|
+int packet_create_data(struct sk_buff_head *queue, struct wireguard_peer *peer, packet_create_data_callback_t callback);
|
|
+void packet_consume_data(struct sk_buff *skb, size_t offset, struct wireguard_device *wg, packet_consume_data_callback_t callback);
|
|
+
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+int packet_init_data_caches(void);
|
|
+void packet_deinit_data_caches(void);
|
|
+#endif
|
|
+
|
|
+#ifdef DEBUG
|
|
+bool packet_counter_selftest(void);
|
|
+#endif
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/peer.h
|
|
@@ -0,0 +1,75 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef PEER_H
|
|
+#define PEER_H
|
|
+
|
|
+#include "noise.h"
|
|
+#include "cookie.h"
|
|
+
|
|
+#include <linux/types.h>
|
|
+#include <linux/netfilter.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/kref.h>
|
|
+#include <net/dst_cache.h>
|
|
+
|
|
+struct wireguard_device;
|
|
+
|
|
+struct endpoint {
|
|
+ union {
|
|
+ struct sockaddr addr;
|
|
+ struct sockaddr_in addr4;
|
|
+ struct sockaddr_in6 addr6;
|
|
+ };
|
|
+ union {
|
|
+ struct in_addr src4;
|
|
+ struct in6_addr src6;
|
|
+ };
|
|
+};
|
|
+
|
|
+struct wireguard_peer {
|
|
+ struct wireguard_device *device;
|
|
+ struct endpoint endpoint;
|
|
+ struct dst_cache endpoint_cache;
|
|
+ rwlock_t endpoint_lock;
|
|
+ struct noise_handshake handshake;
|
|
+ struct noise_keypairs keypairs;
|
|
+ u64 last_sent_handshake;
|
|
+ struct work_struct transmit_handshake_work, clear_peer_work;
|
|
+ struct cookie latest_cookie;
|
|
+ struct hlist_node pubkey_hash;
|
|
+ u64 rx_bytes, tx_bytes;
|
|
+ struct timer_list timer_retransmit_handshake, timer_send_keepalive, timer_new_handshake, timer_kill_ephemerals, timer_persistent_keepalive;
|
|
+ unsigned int timer_handshake_attempts;
|
|
+ unsigned long persistent_keepalive_interval;
|
|
+ bool timers_enabled;
|
|
+ bool timer_need_another_keepalive;
|
|
+ bool need_resend_queue;
|
|
+ bool sent_lastminute_handshake;
|
|
+ struct timeval walltime_last_handshake;
|
|
+ struct sk_buff_head tx_packet_queue;
|
|
+ struct kref refcount;
|
|
+ struct rcu_head rcu;
|
|
+ struct list_head peer_list;
|
|
+ u64 internal_id;
|
|
+#ifdef CONFIG_WIREGUARD_PARALLEL
|
|
+ atomic_t parallel_encryption_inflight;
|
|
+#endif
|
|
+};
|
|
+
|
|
+struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_key[NOISE_PUBLIC_KEY_LEN]);
|
|
+
|
|
+struct wireguard_peer *peer_get(struct wireguard_peer *peer);
|
|
+struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer);
|
|
+
|
|
+void peer_put(struct wireguard_peer *peer);
|
|
+void peer_remove(struct wireguard_peer *peer);
|
|
+void peer_remove_all(struct wireguard_device *wg);
|
|
+
|
|
+struct wireguard_peer *peer_lookup_by_index(struct wireguard_device *wg, u32 index);
|
|
+
|
|
+int peer_for_each_unlocked(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data);
|
|
+int peer_for_each(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data);
|
|
+
|
|
+unsigned int peer_total_count(struct wireguard_device *wg);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/ratelimiter.h
|
|
@@ -0,0 +1,26 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef RATELIMITER_H
|
|
+#define RATELIMITER_H
|
|
+
|
|
+#include <uapi/linux/netfilter/xt_hashlimit.h>
|
|
+
|
|
+struct wireguard_device;
|
|
+struct sk_buff;
|
|
+
|
|
+struct ratelimiter {
|
|
+ struct net *net;
|
|
+ struct xt_hashlimit_mtinfo1 v4_info;
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ struct xt_hashlimit_mtinfo1 v6_info;
|
|
+#endif
|
|
+};
|
|
+
|
|
+int ratelimiter_init(struct ratelimiter *ratelimiter, struct wireguard_device *wg);
|
|
+void ratelimiter_uninit(struct ratelimiter *ratelimiter);
|
|
+bool ratelimiter_allow(struct ratelimiter *ratelimiter, struct sk_buff *skb);
|
|
+
|
|
+int ratelimiter_module_init(void);
|
|
+void ratelimiter_module_deinit(void);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/routingtable.h
|
|
@@ -0,0 +1,40 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef ROUTINGTABLE_H
|
|
+#define ROUTINGTABLE_H
|
|
+
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/ip.h>
|
|
+#include <linux/ipv6.h>
|
|
+
|
|
+struct wireguard_peer;
|
|
+struct routing_table_node;
|
|
+
|
|
+struct routing_table {
|
|
+ struct routing_table_node __rcu *root4;
|
|
+ struct routing_table_node __rcu *root6;
|
|
+ struct mutex table_update_lock;
|
|
+};
|
|
+
|
|
+void routing_table_init(struct routing_table *table);
|
|
+void routing_table_free(struct routing_table *table);
|
|
+int routing_table_insert_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr, struct wireguard_peer *peer);
|
|
+int routing_table_insert_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr, struct wireguard_peer *peer);
|
|
+int routing_table_remove_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr);
|
|
+int routing_table_remove_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr);
|
|
+int routing_table_remove_by_peer(struct routing_table *table, struct wireguard_peer *peer);
|
|
+int routing_table_walk_ips(struct routing_table *table, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family));
|
|
+int routing_table_walk_ips_by_peer(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family));
|
|
+int routing_table_walk_ips_by_peer_sleepable(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family));
|
|
+
|
|
+/* These return a strong reference to a peer: */
|
|
+struct wireguard_peer *routing_table_lookup_v4(struct routing_table *table, const struct in_addr *ip);
|
|
+struct wireguard_peer *routing_table_lookup_v6(struct routing_table *table, const struct in6_addr *ip);
|
|
+struct wireguard_peer *routing_table_lookup_dst(struct routing_table *table, struct sk_buff *skb);
|
|
+struct wireguard_peer *routing_table_lookup_src(struct routing_table *table, struct sk_buff *skb);
|
|
+
|
|
+#ifdef DEBUG
|
|
+bool routing_table_selftest(void);
|
|
+#endif
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/socket.h
|
|
@@ -0,0 +1,24 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef WGSOCKET_H
|
|
+#define WGSOCKET_H
|
|
+
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/udp.h>
|
|
+#include <linux/if_vlan.h>
|
|
+#include <linux/if_ether.h>
|
|
+
|
|
+struct wireguard_device;
|
|
+struct endpoint;
|
|
+
|
|
+int socket_init(struct wireguard_device *wg);
|
|
+void socket_uninit(struct wireguard_device *wg);
|
|
+int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *data, size_t len, u8 ds);
|
|
+int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 ds);
|
|
+int socket_send_buffer_as_reply_to_skb(struct wireguard_device *wg, struct sk_buff *in_skb, void *out_buffer, size_t len);
|
|
+
|
|
+int socket_endpoint_from_skb(struct endpoint *endpoint, struct sk_buff *skb);
|
|
+void socket_set_peer_endpoint(struct wireguard_peer *peer, struct endpoint *endpoint);
|
|
+void socket_clear_peer_endpoint_src(struct wireguard_peer *peer);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/timers.h
|
|
@@ -0,0 +1,19 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef WGTIMERS_H
|
|
+#define WGTIMERS_H
|
|
+
|
|
+struct wireguard_peer;
|
|
+
|
|
+void timers_init_peer(struct wireguard_peer *peer);
|
|
+void timers_uninit_peer(struct wireguard_peer *peer);
|
|
+
|
|
+void timers_data_sent(struct wireguard_peer *peer);
|
|
+void timers_data_received(struct wireguard_peer *peer);
|
|
+void timers_any_authenticated_packet_received(struct wireguard_peer *peer);
|
|
+void timers_handshake_initiated(struct wireguard_peer *peer);
|
|
+void timers_handshake_complete(struct wireguard_peer *peer);
|
|
+void timers_ephemeral_key_created(struct wireguard_peer *peer);
|
|
+void timers_any_authenticated_packet_traversal(struct wireguard_peer *peer);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/uapi.h
|
|
@@ -0,0 +1,159 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ *
|
|
+ * Userspace API for WireGuard
|
|
+ * ---------------------------
|
|
+ *
|
|
+ * ioctl(WG_GET_DEVICE, { .ifr_name: "wg0", .ifr_data: NULL }):
|
|
+ *
|
|
+ * Returns the number of bytes required to hold the peers of a device (`ret_peers_size`).
|
|
+ *
|
|
+ * ioctl(WG_GET_DEVICE, { .ifr_name: "wg0", .ifr_data: user_pointer }):
|
|
+ *
|
|
+ * Retrevies device info, peer info, and ipmask info.
|
|
+ *
|
|
+ * `user_pointer` must point to a region of memory of size `sizeof(struct wgdevice) + ret_peers_size`
|
|
+ * and containing the structure `struct wgdevice { .peers_size: ret_peers_size }`.
|
|
+ *
|
|
+ * Writes to `user_pointer` a succession of structs:
|
|
+ *
|
|
+ * struct wgdevice { .num_peers = 3 }
|
|
+ * struct wgpeer { .num_ipmasks = 4 }
|
|
+ * struct wgipmask
|
|
+ * struct wgipmask
|
|
+ * struct wgipmask
|
|
+ * struct wgipmask
|
|
+ * struct wgpeer { .num_ipmasks = 2 }
|
|
+ * struct wgipmask
|
|
+ * struct wgipmask
|
|
+ * struct wgpeer { .num_ipmasks = 0 }
|
|
+ *
|
|
+ * Returns 0 on success. Returns -EMSGSIZE if there is too much data for the size of passed-in
|
|
+ * memory, in which case, this should be recalculated using the call above. Returns -errno if
|
|
+ * another error occured.
|
|
+ *
|
|
+ * ioctl(WG_SET_DEVICE, { .ifr_name: "wg0", .ifr_data: user_pointer }):
|
|
+ *
|
|
+ * Sets device info, peer info, and ipmask info.
|
|
+ *
|
|
+ * `user_pointer` must point to a region of memory containing a succession of structs:
|
|
+ *
|
|
+ * struct wgdevice { .num_peers = 3 }
|
|
+ * struct wgpeer { .num_ipmasks = 4 }
|
|
+ * struct wgipmask
|
|
+ * struct wgipmask
|
|
+ * struct wgipmask
|
|
+ * struct wgipmask
|
|
+ * struct wgpeer { .num_ipmasks = 2 }
|
|
+ * struct wgipmask
|
|
+ * struct wgipmask
|
|
+ * struct wgpeer { .num_ipmasks = 0 }
|
|
+ *
|
|
+ * If `wgdevice->flags & WGDEVICE_REPLACE_PEERS` is true, removes all peers of device before adding new ones.
|
|
+ * If `wgpeer->flags & WGPEER_REMOVE_ME` is true, the peer identified by `wgpeer->public_key` is removed.
|
|
+ * If `wgpeer->flags & WGPEER_REPLACE_IPMASKS` is true, removes all ipmasks before adding new ones.
|
|
+ * If `wgdevice->private_key` is filled with zeros, no action is taken on the private key.
|
|
+ * If `wgdevice->preshared_key` is filled with zeros, no action is taken on the pre-shared key.
|
|
+ * If `wgdevice->flags & WGDEVICE_REMOVE_PRIVATE_KEY` is true, the private key is removed.
|
|
+ * If `wgdevice->flags & WGDEVICE_REMOVE_PRESHARED_KEY` is true, the pre-shared key is removed.
|
|
+ *
|
|
+ * Returns 0 on success, or -errno if an error occurred.
|
|
+ */
|
|
+
|
|
+
|
|
+#ifndef WGUAPI_H
|
|
+#define WGUAPI_H
|
|
+
|
|
+#ifdef __linux__
|
|
+#include <linux/types.h>
|
|
+#else
|
|
+#include <stdint.h>
|
|
+typedef uint8_t __u8;
|
|
+typedef uint16_t __u16;
|
|
+typedef uint32_t __u32;
|
|
+typedef uint64_t __u64;
|
|
+typedef int32_t __s32;
|
|
+#endif
|
|
+#ifdef __KERNEL__
|
|
+#include <linux/time.h>
|
|
+#include <linux/socket.h>
|
|
+#else
|
|
+#include <net/if.h>
|
|
+#include <netinet/in.h>
|
|
+#include <sys/time.h>
|
|
+#include <sys/socket.h>
|
|
+#endif
|
|
+
|
|
+#define WG_GET_DEVICE (SIOCDEVPRIVATE + 0)
|
|
+#define WG_SET_DEVICE (SIOCDEVPRIVATE + 1)
|
|
+
|
|
+#define WG_KEY_LEN 32
|
|
+
|
|
+struct wgipmask {
|
|
+ __s32 family;
|
|
+ union {
|
|
+ struct in_addr ip4;
|
|
+ struct in6_addr ip6;
|
|
+ };
|
|
+ __u8 cidr;
|
|
+};
|
|
+
|
|
+enum {
|
|
+ WGPEER_REMOVE_ME = (1 << 0),
|
|
+ WGPEER_REPLACE_IPMASKS = (1 << 1)
|
|
+};
|
|
+struct wgpeer {
|
|
+ __u8 public_key[WG_KEY_LEN]; /* Get/Set */
|
|
+ __u32 flags; /* Set */
|
|
+
|
|
+ union {
|
|
+ struct sockaddr addr;
|
|
+ struct sockaddr_in addr4;
|
|
+ struct sockaddr_in6 addr6;
|
|
+ } endpoint; /* Get/Set */
|
|
+
|
|
+ struct timeval last_handshake_time; /* Get */
|
|
+ __u64 rx_bytes, tx_bytes; /* Get */
|
|
+ __u16 persistent_keepalive_interval; /* Get/Set -- 0 = off, 0xffff = unset */
|
|
+
|
|
+ __u16 num_ipmasks; /* Get/Set */
|
|
+};
|
|
+
|
|
+enum {
|
|
+ WGDEVICE_REPLACE_PEERS = (1 << 0),
|
|
+ WGDEVICE_REMOVE_PRIVATE_KEY = (1 << 1),
|
|
+ WGDEVICE_REMOVE_PRESHARED_KEY = (1 << 2),
|
|
+ WGDEVICE_REMOVE_FWMARK = (1 << 3)
|
|
+};
|
|
+struct wgdevice {
|
|
+ char interface[IFNAMSIZ]; /* Get */
|
|
+ __u32 flags; /* Set */
|
|
+
|
|
+ __u8 public_key[WG_KEY_LEN]; /* Get */
|
|
+ __u8 private_key[WG_KEY_LEN]; /* Get/Set */
|
|
+ __u8 preshared_key[WG_KEY_LEN]; /* Get/Set */
|
|
+ __u32 fwmark; /* Get/Set */
|
|
+ __u16 port; /* Get/Set */
|
|
+
|
|
+ union {
|
|
+ __u16 num_peers; /* Get/Set */
|
|
+ __u32 peers_size; /* Get */
|
|
+ };
|
|
+};
|
|
+
|
|
+/* These are simply for convenience in iterating. It allows you to write something like:
|
|
+ *
|
|
+ * for_each_wgpeer(device, peer, i) {
|
|
+ * for_each_wgipmask(peer, ipmask, j) {
|
|
+ * do_something_with_ipmask(ipmask);
|
|
+ * }
|
|
+ * }
|
|
+ */
|
|
+#define for_each_wgpeer(__dev, __peer, __i) for ((__i) = 0, (__peer) = (struct wgpeer *)((uint8_t *)(__dev) + sizeof(struct wgdevice)); \
|
|
+ (__i) < (__dev)->num_peers; \
|
|
+ ++(__i), (__peer) = (struct wgpeer *)((uint8_t *)(__peer) + sizeof(struct wgpeer) + (sizeof(struct wgipmask) * (__peer)->num_ipmasks)))
|
|
+
|
|
+#define for_each_wgipmask(__peer, __ipmask, __i) for ((__i) = 0, (__ipmask) = (struct wgipmask *)((uint8_t *)(__peer) + sizeof(struct wgpeer)); \
|
|
+ (__i) < (__peer)->num_ipmasks; \
|
|
+ ++(__i), (__ipmask) = (struct wgipmask *)((uint8_t *)(__ipmask) + sizeof(struct wgipmask)))
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/version.h
|
|
@@ -0,0 +1 @@
|
|
+#define WIREGUARD_VERSION "0.0.20170223"
|
|
--- /dev/null
|
|
+++ b/net/wireguard/selftest/blake2s.h
|
|
@@ -0,0 +1,556 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifdef DEBUG
|
|
+static const u8 blake2s_testvecs[][BLAKE2S_OUTBYTES] = {
|
|
+ { 0x69, 0x21, 0x7A, 0x30, 0x79, 0x90, 0x80, 0x94, 0xE1, 0x11, 0x21, 0xD0, 0x42, 0x35, 0x4A, 0x7C, 0x1F, 0x55, 0xB6, 0x48, 0x2C, 0xA1, 0xA5, 0x1E, 0x1B, 0x25, 0x0D, 0xFD, 0x1E, 0xD0, 0xEE, 0xF9 },
|
|
+ { 0xE3, 0x4D, 0x74, 0xDB, 0xAF, 0x4F, 0xF4, 0xC6, 0xAB, 0xD8, 0x71, 0xCC, 0x22, 0x04, 0x51, 0xD2, 0xEA, 0x26, 0x48, 0x84, 0x6C, 0x77, 0x57, 0xFB, 0xAA, 0xC8, 0x2F, 0xE5, 0x1A, 0xD6, 0x4B, 0xEA },
|
|
+ { 0xDD, 0xAD, 0x9A, 0xB1, 0x5D, 0xAC, 0x45, 0x49, 0xBA, 0x42, 0xF4, 0x9D, 0x26, 0x24, 0x96, 0xBE, 0xF6, 0xC0, 0xBA, 0xE1, 0xDD, 0x34, 0x2A, 0x88, 0x08, 0xF8, 0xEA, 0x26, 0x7C, 0x6E, 0x21, 0x0C },
|
|
+ { 0xE8, 0xF9, 0x1C, 0x6E, 0xF2, 0x32, 0xA0, 0x41, 0x45, 0x2A, 0xB0, 0xE1, 0x49, 0x07, 0x0C, 0xDD, 0x7D, 0xD1, 0x76, 0x9E, 0x75, 0xB3, 0xA5, 0x92, 0x1B, 0xE3, 0x78, 0x76, 0xC4, 0x5C, 0x99, 0x00 },
|
|
+ { 0x0C, 0xC7, 0x0E, 0x00, 0x34, 0x8B, 0x86, 0xBA, 0x29, 0x44, 0xD0, 0xC3, 0x20, 0x38, 0xB2, 0x5C, 0x55, 0x58, 0x4F, 0x90, 0xDF, 0x23, 0x04, 0xF5, 0x5F, 0xA3, 0x32, 0xAF, 0x5F, 0xB0, 0x1E, 0x20 },
|
|
+ { 0xEC, 0x19, 0x64, 0x19, 0x10, 0x87, 0xA4, 0xFE, 0x9D, 0xF1, 0xC7, 0x95, 0x34, 0x2A, 0x02, 0xFF, 0xC1, 0x91, 0xA5, 0xB2, 0x51, 0x76, 0x48, 0x56, 0xAE, 0x5B, 0x8B, 0x57, 0x69, 0xF0, 0xC6, 0xCD },
|
|
+ { 0xE1, 0xFA, 0x51, 0x61, 0x8D, 0x7D, 0xF4, 0xEB, 0x70, 0xCF, 0x0D, 0x5A, 0x9E, 0x90, 0x6F, 0x80, 0x6E, 0x9D, 0x19, 0xF7, 0xF4, 0xF0, 0x1E, 0x3B, 0x62, 0x12, 0x88, 0xE4, 0x12, 0x04, 0x05, 0xD6 },
|
|
+ { 0x59, 0x80, 0x01, 0xFA, 0xFB, 0xE8, 0xF9, 0x4E, 0xC6, 0x6D, 0xC8, 0x27, 0xD0, 0x12, 0xCF, 0xCB, 0xBA, 0x22, 0x28, 0x56, 0x9F, 0x44, 0x8E, 0x89, 0xEA, 0x22, 0x08, 0xC8, 0xBF, 0x76, 0x92, 0x93 },
|
|
+ { 0xC7, 0xE8, 0x87, 0xB5, 0x46, 0x62, 0x36, 0x35, 0xE9, 0x3E, 0x04, 0x95, 0x59, 0x8F, 0x17, 0x26, 0x82, 0x19, 0x96, 0xC2, 0x37, 0x77, 0x05, 0xB9, 0x3A, 0x1F, 0x63, 0x6F, 0x87, 0x2B, 0xFA, 0x2D },
|
|
+ { 0xC3, 0x15, 0xA4, 0x37, 0xDD, 0x28, 0x06, 0x2A, 0x77, 0x0D, 0x48, 0x19, 0x67, 0x13, 0x6B, 0x1B, 0x5E, 0xB8, 0x8B, 0x21, 0xEE, 0x53, 0xD0, 0x32, 0x9C, 0x58, 0x97, 0x12, 0x6E, 0x9D, 0xB0, 0x2C },
|
|
+ { 0xBB, 0x47, 0x3D, 0xED, 0xDC, 0x05, 0x5F, 0xEA, 0x62, 0x28, 0xF2, 0x07, 0xDA, 0x57, 0x53, 0x47, 0xBB, 0x00, 0x40, 0x4C, 0xD3, 0x49, 0xD3, 0x8C, 0x18, 0x02, 0x63, 0x07, 0xA2, 0x24, 0xCB, 0xFF },
|
|
+ { 0x68, 0x7E, 0x18, 0x73, 0xA8, 0x27, 0x75, 0x91, 0xBB, 0x33, 0xD9, 0xAD, 0xF9, 0xA1, 0x39, 0x12, 0xEF, 0xEF, 0xE5, 0x57, 0xCA, 0xFC, 0x39, 0xA7, 0x95, 0x26, 0x23, 0xE4, 0x72, 0x55, 0xF1, 0x6D },
|
|
+ { 0x1A, 0xC7, 0xBA, 0x75, 0x4D, 0x6E, 0x2F, 0x94, 0xE0, 0xE8, 0x6C, 0x46, 0xBF, 0xB2, 0x62, 0xAB, 0xBB, 0x74, 0xF4, 0x50, 0xEF, 0x45, 0x6D, 0x6B, 0x4D, 0x97, 0xAA, 0x80, 0xCE, 0x6D, 0xA7, 0x67 },
|
|
+ { 0x01, 0x2C, 0x97, 0x80, 0x96, 0x14, 0x81, 0x6B, 0x5D, 0x94, 0x94, 0x47, 0x7D, 0x4B, 0x68, 0x7D, 0x15, 0xB9, 0x6E, 0xB6, 0x9C, 0x0E, 0x80, 0x74, 0xA8, 0x51, 0x6F, 0x31, 0x22, 0x4B, 0x5C, 0x98 },
|
|
+ { 0x91, 0xFF, 0xD2, 0x6C, 0xFA, 0x4D, 0xA5, 0x13, 0x4C, 0x7E, 0xA2, 0x62, 0xF7, 0x88, 0x9C, 0x32, 0x9F, 0x61, 0xF6, 0xA6, 0x57, 0x22, 0x5C, 0xC2, 0x12, 0xF4, 0x00, 0x56, 0xD9, 0x86, 0xB3, 0xF4 },
|
|
+ { 0xD9, 0x7C, 0x82, 0x8D, 0x81, 0x82, 0xA7, 0x21, 0x80, 0xA0, 0x6A, 0x78, 0x26, 0x83, 0x30, 0x67, 0x3F, 0x7C, 0x4E, 0x06, 0x35, 0x94, 0x7C, 0x04, 0xC0, 0x23, 0x23, 0xFD, 0x45, 0xC0, 0xA5, 0x2D },
|
|
+ { 0xEF, 0xC0, 0x4C, 0xDC, 0x39, 0x1C, 0x7E, 0x91, 0x19, 0xBD, 0x38, 0x66, 0x8A, 0x53, 0x4E, 0x65, 0xFE, 0x31, 0x03, 0x6D, 0x6A, 0x62, 0x11, 0x2E, 0x44, 0xEB, 0xEB, 0x11, 0xF9, 0xC5, 0x70, 0x80 },
|
|
+ { 0x99, 0x2C, 0xF5, 0xC0, 0x53, 0x44, 0x2A, 0x5F, 0xBC, 0x4F, 0xAF, 0x58, 0x3E, 0x04, 0xE5, 0x0B, 0xB7, 0x0D, 0x2F, 0x39, 0xFB, 0xB6, 0xA5, 0x03, 0xF8, 0x9E, 0x56, 0xA6, 0x3E, 0x18, 0x57, 0x8A },
|
|
+ { 0x38, 0x64, 0x0E, 0x9F, 0x21, 0x98, 0x3E, 0x67, 0xB5, 0x39, 0xCA, 0xCC, 0xAE, 0x5E, 0xCF, 0x61, 0x5A, 0xE2, 0x76, 0x4F, 0x75, 0xA0, 0x9C, 0x9C, 0x59, 0xB7, 0x64, 0x83, 0xC1, 0xFB, 0xC7, 0x35 },
|
|
+ { 0x21, 0x3D, 0xD3, 0x4C, 0x7E, 0xFE, 0x4F, 0xB2, 0x7A, 0x6B, 0x35, 0xF6, 0xB4, 0x00, 0x0D, 0x1F, 0xE0, 0x32, 0x81, 0xAF, 0x3C, 0x72, 0x3E, 0x5C, 0x9F, 0x94, 0x74, 0x7A, 0x5F, 0x31, 0xCD, 0x3B },
|
|
+ { 0xEC, 0x24, 0x6E, 0xEE, 0xB9, 0xCE, 0xD3, 0xF7, 0xAD, 0x33, 0xED, 0x28, 0x66, 0x0D, 0xD9, 0xBB, 0x07, 0x32, 0x51, 0x3D, 0xB4, 0xE2, 0xFA, 0x27, 0x8B, 0x60, 0xCD, 0xE3, 0x68, 0x2A, 0x4C, 0xCD },
|
|
+ { 0xAC, 0x9B, 0x61, 0xD4, 0x46, 0x64, 0x8C, 0x30, 0x05, 0xD7, 0x89, 0x2B, 0xF3, 0xA8, 0x71, 0x9F, 0x4C, 0x81, 0x81, 0xCF, 0xDC, 0xBC, 0x2B, 0x79, 0xFE, 0xF1, 0x0A, 0x27, 0x9B, 0x91, 0x10, 0x95 },
|
|
+ { 0x7B, 0xF8, 0xB2, 0x29, 0x59, 0xE3, 0x4E, 0x3A, 0x43, 0xF7, 0x07, 0x92, 0x23, 0xE8, 0x3A, 0x97, 0x54, 0x61, 0x7D, 0x39, 0x1E, 0x21, 0x3D, 0xFD, 0x80, 0x8E, 0x41, 0xB9, 0xBE, 0xAD, 0x4C, 0xE7 },
|
|
+ { 0x68, 0xD4, 0xB5, 0xD4, 0xFA, 0x0E, 0x30, 0x2B, 0x64, 0xCC, 0xC5, 0xAF, 0x79, 0x29, 0x13, 0xAC, 0x4C, 0x88, 0xEC, 0x95, 0xC0, 0x7D, 0xDF, 0x40, 0x69, 0x42, 0x56, 0xEB, 0x88, 0xCE, 0x9F, 0x3D },
|
|
+ { 0xB2, 0xC2, 0x42, 0x0F, 0x05, 0xF9, 0xAB, 0xE3, 0x63, 0x15, 0x91, 0x93, 0x36, 0xB3, 0x7E, 0x4E, 0x0F, 0xA3, 0x3F, 0xF7, 0xE7, 0x6A, 0x49, 0x27, 0x67, 0x00, 0x6F, 0xDB, 0x5D, 0x93, 0x54, 0x62 },
|
|
+ { 0x13, 0x4F, 0x61, 0xBB, 0xD0, 0xBB, 0xB6, 0x9A, 0xED, 0x53, 0x43, 0x90, 0x45, 0x51, 0xA3, 0xE6, 0xC1, 0xAA, 0x7D, 0xCD, 0xD7, 0x7E, 0x90, 0x3E, 0x70, 0x23, 0xEB, 0x7C, 0x60, 0x32, 0x0A, 0xA7 },
|
|
+ { 0x46, 0x93, 0xF9, 0xBF, 0xF7, 0xD4, 0xF3, 0x98, 0x6A, 0x7D, 0x17, 0x6E, 0x6E, 0x06, 0xF7, 0x2A, 0xD1, 0x49, 0x0D, 0x80, 0x5C, 0x99, 0xE2, 0x53, 0x47, 0xB8, 0xDE, 0x77, 0xB4, 0xDB, 0x6D, 0x9B },
|
|
+ { 0x85, 0x3E, 0x26, 0xF7, 0x41, 0x95, 0x3B, 0x0F, 0xD5, 0xBD, 0xB4, 0x24, 0xE8, 0xAB, 0x9E, 0x8B, 0x37, 0x50, 0xEA, 0xA8, 0xEF, 0x61, 0xE4, 0x79, 0x02, 0xC9, 0x1E, 0x55, 0x4E, 0x9C, 0x73, 0xB9 },
|
|
+ { 0xF7, 0xDE, 0x53, 0x63, 0x61, 0xAB, 0xAA, 0x0E, 0x15, 0x81, 0x56, 0xCF, 0x0E, 0xA4, 0xF6, 0x3A, 0x99, 0xB5, 0xE4, 0x05, 0x4F, 0x8F, 0xA4, 0xC9, 0xD4, 0x5F, 0x62, 0x85, 0xCA, 0xD5, 0x56, 0x94 },
|
|
+ { 0x4C, 0x23, 0x06, 0x08, 0x86, 0x0A, 0x99, 0xAE, 0x8D, 0x7B, 0xD5, 0xC2, 0xCC, 0x17, 0xFA, 0x52, 0x09, 0x6B, 0x9A, 0x61, 0xBE, 0xDB, 0x17, 0xCB, 0x76, 0x17, 0x86, 0x4A, 0xD2, 0x9C, 0xA7, 0xA6 },
|
|
+ { 0xAE, 0xB9, 0x20, 0xEA, 0x87, 0x95, 0x2D, 0xAD, 0xB1, 0xFB, 0x75, 0x92, 0x91, 0xE3, 0x38, 0x81, 0x39, 0xA8, 0x72, 0x86, 0x50, 0x01, 0x88, 0x6E, 0xD8, 0x47, 0x52, 0xE9, 0x3C, 0x25, 0x0C, 0x2A },
|
|
+ { 0xAB, 0xA4, 0xAD, 0x9B, 0x48, 0x0B, 0x9D, 0xF3, 0xD0, 0x8C, 0xA5, 0xE8, 0x7B, 0x0C, 0x24, 0x40, 0xD4, 0xE4, 0xEA, 0x21, 0x22, 0x4C, 0x2E, 0xB4, 0x2C, 0xBA, 0xE4, 0x69, 0xD0, 0x89, 0xB9, 0x31 },
|
|
+ { 0x05, 0x82, 0x56, 0x07, 0xD7, 0xFD, 0xF2, 0xD8, 0x2E, 0xF4, 0xC3, 0xC8, 0xC2, 0xAE, 0xA9, 0x61, 0xAD, 0x98, 0xD6, 0x0E, 0xDF, 0xF7, 0xD0, 0x18, 0x98, 0x3E, 0x21, 0x20, 0x4C, 0x0D, 0x93, 0xD1 },
|
|
+ { 0xA7, 0x42, 0xF8, 0xB6, 0xAF, 0x82, 0xD8, 0xA6, 0xCA, 0x23, 0x57, 0xC5, 0xF1, 0xCF, 0x91, 0xDE, 0xFB, 0xD0, 0x66, 0x26, 0x7D, 0x75, 0xC0, 0x48, 0xB3, 0x52, 0x36, 0x65, 0x85, 0x02, 0x59, 0x62 },
|
|
+ { 0x2B, 0xCA, 0xC8, 0x95, 0x99, 0x00, 0x0B, 0x42, 0xC9, 0x5A, 0xE2, 0x38, 0x35, 0xA7, 0x13, 0x70, 0x4E, 0xD7, 0x97, 0x89, 0xC8, 0x4F, 0xEF, 0x14, 0x9A, 0x87, 0x4F, 0xF7, 0x33, 0xF0, 0x17, 0xA2 },
|
|
+ { 0xAC, 0x1E, 0xD0, 0x7D, 0x04, 0x8F, 0x10, 0x5A, 0x9E, 0x5B, 0x7A, 0xB8, 0x5B, 0x09, 0xA4, 0x92, 0xD5, 0xBA, 0xFF, 0x14, 0xB8, 0xBF, 0xB0, 0xE9, 0xFD, 0x78, 0x94, 0x86, 0xEE, 0xA2, 0xB9, 0x74 },
|
|
+ { 0xE4, 0x8D, 0x0E, 0xCF, 0xAF, 0x49, 0x7D, 0x5B, 0x27, 0xC2, 0x5D, 0x99, 0xE1, 0x56, 0xCB, 0x05, 0x79, 0xD4, 0x40, 0xD6, 0xE3, 0x1F, 0xB6, 0x24, 0x73, 0x69, 0x6D, 0xBF, 0x95, 0xE0, 0x10, 0xE4 },
|
|
+ { 0x12, 0xA9, 0x1F, 0xAD, 0xF8, 0xB2, 0x16, 0x44, 0xFD, 0x0F, 0x93, 0x4F, 0x3C, 0x4A, 0x8F, 0x62, 0xBA, 0x86, 0x2F, 0xFD, 0x20, 0xE8, 0xE9, 0x61, 0x15, 0x4C, 0x15, 0xC1, 0x38, 0x84, 0xED, 0x3D },
|
|
+ { 0x7C, 0xBE, 0xE9, 0x6E, 0x13, 0x98, 0x97, 0xDC, 0x98, 0xFB, 0xEF, 0x3B, 0xE8, 0x1A, 0xD4, 0xD9, 0x64, 0xD2, 0x35, 0xCB, 0x12, 0x14, 0x1F, 0xB6, 0x67, 0x27, 0xE6, 0xE5, 0xDF, 0x73, 0xA8, 0x78 },
|
|
+ { 0xEB, 0xF6, 0x6A, 0xBB, 0x59, 0x7A, 0xE5, 0x72, 0xA7, 0x29, 0x7C, 0xB0, 0x87, 0x1E, 0x35, 0x5A, 0xCC, 0xAF, 0xAD, 0x83, 0x77, 0xB8, 0xE7, 0x8B, 0xF1, 0x64, 0xCE, 0x2A, 0x18, 0xDE, 0x4B, 0xAF },
|
|
+ { 0x71, 0xB9, 0x33, 0xB0, 0x7E, 0x4F, 0xF7, 0x81, 0x8C, 0xE0, 0x59, 0xD0, 0x08, 0x82, 0x9E, 0x45, 0x3C, 0x6F, 0xF0, 0x2E, 0xC0, 0xA7, 0xDB, 0x39, 0x3F, 0xC2, 0xD8, 0x70, 0xF3, 0x7A, 0x72, 0x86 },
|
|
+ { 0x7C, 0xF7, 0xC5, 0x13, 0x31, 0x22, 0x0B, 0x8D, 0x3E, 0xBA, 0xED, 0x9C, 0x29, 0x39, 0x8A, 0x16, 0xD9, 0x81, 0x56, 0xE2, 0x61, 0x3C, 0xB0, 0x88, 0xF2, 0xB0, 0xE0, 0x8A, 0x1B, 0xE4, 0xCF, 0x4F },
|
|
+ { 0x3E, 0x41, 0xA1, 0x08, 0xE0, 0xF6, 0x4A, 0xD2, 0x76, 0xB9, 0x79, 0xE1, 0xCE, 0x06, 0x82, 0x79, 0xE1, 0x6F, 0x7B, 0xC7, 0xE4, 0xAA, 0x1D, 0x21, 0x1E, 0x17, 0xB8, 0x11, 0x61, 0xDF, 0x16, 0x02 },
|
|
+ { 0x88, 0x65, 0x02, 0xA8, 0x2A, 0xB4, 0x7B, 0xA8, 0xD8, 0x67, 0x10, 0xAA, 0x9D, 0xE3, 0xD4, 0x6E, 0xA6, 0x5C, 0x47, 0xAF, 0x6E, 0xE8, 0xDE, 0x45, 0x0C, 0xCE, 0xB8, 0xB1, 0x1B, 0x04, 0x5F, 0x50 },
|
|
+ { 0xC0, 0x21, 0xBC, 0x5F, 0x09, 0x54, 0xFE, 0xE9, 0x4F, 0x46, 0xEA, 0x09, 0x48, 0x7E, 0x10, 0xA8, 0x48, 0x40, 0xD0, 0x2F, 0x64, 0x81, 0x0B, 0xC0, 0x8D, 0x9E, 0x55, 0x1F, 0x7D, 0x41, 0x68, 0x14 },
|
|
+ { 0x20, 0x30, 0x51, 0x6E, 0x8A, 0x5F, 0xE1, 0x9A, 0xE7, 0x9C, 0x33, 0x6F, 0xCE, 0x26, 0x38, 0x2A, 0x74, 0x9D, 0x3F, 0xD0, 0xEC, 0x91, 0xE5, 0x37, 0xD4, 0xBD, 0x23, 0x58, 0xC1, 0x2D, 0xFB, 0x22 },
|
|
+ { 0x55, 0x66, 0x98, 0xDA, 0xC8, 0x31, 0x7F, 0xD3, 0x6D, 0xFB, 0xDF, 0x25, 0xA7, 0x9C, 0xB1, 0x12, 0xD5, 0x42, 0x58, 0x60, 0x60, 0x5C, 0xBA, 0xF5, 0x07, 0xF2, 0x3B, 0xF7, 0xE9, 0xF4, 0x2A, 0xFE },
|
|
+ { 0x2F, 0x86, 0x7B, 0xA6, 0x77, 0x73, 0xFD, 0xC3, 0xE9, 0x2F, 0xCE, 0xD9, 0x9A, 0x64, 0x09, 0xAD, 0x39, 0xD0, 0xB8, 0x80, 0xFD, 0xE8, 0xF1, 0x09, 0xA8, 0x17, 0x30, 0xC4, 0x45, 0x1D, 0x01, 0x78 },
|
|
+ { 0x17, 0x2E, 0xC2, 0x18, 0xF1, 0x19, 0xDF, 0xAE, 0x98, 0x89, 0x6D, 0xFF, 0x29, 0xDD, 0x98, 0x76, 0xC9, 0x4A, 0xF8, 0x74, 0x17, 0xF9, 0xAE, 0x4C, 0x70, 0x14, 0xBB, 0x4E, 0x4B, 0x96, 0xAF, 0xC7 },
|
|
+ { 0x3F, 0x85, 0x81, 0x4A, 0x18, 0x19, 0x5F, 0x87, 0x9A, 0xA9, 0x62, 0xF9, 0x5D, 0x26, 0xBD, 0x82, 0xA2, 0x78, 0xF2, 0xB8, 0x23, 0x20, 0x21, 0x8F, 0x6B, 0x3B, 0xD6, 0xF7, 0xF6, 0x67, 0xA6, 0xD9 },
|
|
+ { 0x1B, 0x61, 0x8F, 0xBA, 0xA5, 0x66, 0xB3, 0xD4, 0x98, 0xC1, 0x2E, 0x98, 0x2C, 0x9E, 0xC5, 0x2E, 0x4D, 0xA8, 0x5A, 0x8C, 0x54, 0xF3, 0x8F, 0x34, 0xC0, 0x90, 0x39, 0x4F, 0x23, 0xC1, 0x84, 0xC1 },
|
|
+ { 0x0C, 0x75, 0x8F, 0xB5, 0x69, 0x2F, 0xFD, 0x41, 0xA3, 0x57, 0x5D, 0x0A, 0xF0, 0x0C, 0xC7, 0xFB, 0xF2, 0xCB, 0xE5, 0x90, 0x5A, 0x58, 0x32, 0x3A, 0x88, 0xAE, 0x42, 0x44, 0xF6, 0xE4, 0xC9, 0x93 },
|
|
+ { 0xA9, 0x31, 0x36, 0x0C, 0xAD, 0x62, 0x8C, 0x7F, 0x12, 0xA6, 0xC1, 0xC4, 0xB7, 0x53, 0xB0, 0xF4, 0x06, 0x2A, 0xEF, 0x3C, 0xE6, 0x5A, 0x1A, 0xE3, 0xF1, 0x93, 0x69, 0xDA, 0xDF, 0x3A, 0xE2, 0x3D },
|
|
+ { 0xCB, 0xAC, 0x7D, 0x77, 0x3B, 0x1E, 0x3B, 0x3C, 0x66, 0x91, 0xD7, 0xAB, 0xB7, 0xE9, 0xDF, 0x04, 0x5C, 0x8B, 0xA1, 0x92, 0x68, 0xDE, 0xD1, 0x53, 0x20, 0x7F, 0x5E, 0x80, 0x43, 0x52, 0xEC, 0x5D },
|
|
+ { 0x23, 0xA1, 0x96, 0xD3, 0x80, 0x2E, 0xD3, 0xC1, 0xB3, 0x84, 0x01, 0x9A, 0x82, 0x32, 0x58, 0x40, 0xD3, 0x2F, 0x71, 0x95, 0x0C, 0x45, 0x80, 0xB0, 0x34, 0x45, 0xE0, 0x89, 0x8E, 0x14, 0x05, 0x3C },
|
|
+ { 0xF4, 0x49, 0x54, 0x70, 0xF2, 0x26, 0xC8, 0xC2, 0x14, 0xBE, 0x08, 0xFD, 0xFA, 0xD4, 0xBC, 0x4A, 0x2A, 0x9D, 0xBE, 0xA9, 0x13, 0x6A, 0x21, 0x0D, 0xF0, 0xD4, 0xB6, 0x49, 0x29, 0xE6, 0xFC, 0x14 },
|
|
+ { 0xE2, 0x90, 0xDD, 0x27, 0x0B, 0x46, 0x7F, 0x34, 0xAB, 0x1C, 0x00, 0x2D, 0x34, 0x0F, 0xA0, 0x16, 0x25, 0x7F, 0xF1, 0x9E, 0x58, 0x33, 0xFD, 0xBB, 0xF2, 0xCB, 0x40, 0x1C, 0x3B, 0x28, 0x17, 0xDE },
|
|
+ { 0x9F, 0xC7, 0xB5, 0xDE, 0xD3, 0xC1, 0x50, 0x42, 0xB2, 0xA6, 0x58, 0x2D, 0xC3, 0x9B, 0xE0, 0x16, 0xD2, 0x4A, 0x68, 0x2D, 0x5E, 0x61, 0xAD, 0x1E, 0xFF, 0x9C, 0x63, 0x30, 0x98, 0x48, 0xF7, 0x06 },
|
|
+ { 0x8C, 0xCA, 0x67, 0xA3, 0x6D, 0x17, 0xD5, 0xE6, 0x34, 0x1C, 0xB5, 0x92, 0xFD, 0x7B, 0xEF, 0x99, 0x26, 0xC9, 0xE3, 0xAA, 0x10, 0x27, 0xEA, 0x11, 0xA7, 0xD8, 0xBD, 0x26, 0x0B, 0x57, 0x6E, 0x04 },
|
|
+ { 0x40, 0x93, 0x92, 0xF5, 0x60, 0xF8, 0x68, 0x31, 0xDA, 0x43, 0x73, 0xEE, 0x5E, 0x00, 0x74, 0x26, 0x05, 0x95, 0xD7, 0xBC, 0x24, 0x18, 0x3B, 0x60, 0xED, 0x70, 0x0D, 0x45, 0x83, 0xD3, 0xF6, 0xF0 },
|
|
+ { 0x28, 0x02, 0x16, 0x5D, 0xE0, 0x90, 0x91, 0x55, 0x46, 0xF3, 0x39, 0x8C, 0xD8, 0x49, 0x16, 0x4A, 0x19, 0xF9, 0x2A, 0xDB, 0xC3, 0x61, 0xAD, 0xC9, 0x9B, 0x0F, 0x20, 0xC8, 0xEA, 0x07, 0x10, 0x54 },
|
|
+ { 0xAD, 0x83, 0x91, 0x68, 0xD9, 0xF8, 0xA4, 0xBE, 0x95, 0xBA, 0x9E, 0xF9, 0xA6, 0x92, 0xF0, 0x72, 0x56, 0xAE, 0x43, 0xFE, 0x6F, 0x98, 0x64, 0xE2, 0x90, 0x69, 0x1B, 0x02, 0x56, 0xCE, 0x50, 0xA9 },
|
|
+ { 0x75, 0xFD, 0xAA, 0x50, 0x38, 0xC2, 0x84, 0xB8, 0x6D, 0x6E, 0x8A, 0xFF, 0xE8, 0xB2, 0x80, 0x7E, 0x46, 0x7B, 0x86, 0x60, 0x0E, 0x79, 0xAF, 0x36, 0x89, 0xFB, 0xC0, 0x63, 0x28, 0xCB, 0xF8, 0x94 },
|
|
+ { 0xE5, 0x7C, 0xB7, 0x94, 0x87, 0xDD, 0x57, 0x90, 0x24, 0x32, 0xB2, 0x50, 0x73, 0x38, 0x13, 0xBD, 0x96, 0xA8, 0x4E, 0xFC, 0xE5, 0x9F, 0x65, 0x0F, 0xAC, 0x26, 0xE6, 0x69, 0x6A, 0xEF, 0xAF, 0xC3 },
|
|
+ { 0x56, 0xF3, 0x4E, 0x8B, 0x96, 0x55, 0x7E, 0x90, 0xC1, 0xF2, 0x4B, 0x52, 0xD0, 0xC8, 0x9D, 0x51, 0x08, 0x6A, 0xCF, 0x1B, 0x00, 0xF6, 0x34, 0xCF, 0x1D, 0xDE, 0x92, 0x33, 0xB8, 0xEA, 0xAA, 0x3E },
|
|
+ { 0x1B, 0x53, 0xEE, 0x94, 0xAA, 0xF3, 0x4E, 0x4B, 0x15, 0x9D, 0x48, 0xDE, 0x35, 0x2C, 0x7F, 0x06, 0x61, 0xD0, 0xA4, 0x0E, 0xDF, 0xF9, 0x5A, 0x0B, 0x16, 0x39, 0xB4, 0x09, 0x0E, 0x97, 0x44, 0x72 },
|
|
+ { 0x05, 0x70, 0x5E, 0x2A, 0x81, 0x75, 0x7C, 0x14, 0xBD, 0x38, 0x3E, 0xA9, 0x8D, 0xDA, 0x54, 0x4E, 0xB1, 0x0E, 0x6B, 0xC0, 0x7B, 0xAE, 0x43, 0x5E, 0x25, 0x18, 0xDB, 0xE1, 0x33, 0x52, 0x53, 0x75 },
|
|
+ { 0xD8, 0xB2, 0x86, 0x6E, 0x8A, 0x30, 0x9D, 0xB5, 0x3E, 0x52, 0x9E, 0xC3, 0x29, 0x11, 0xD8, 0x2F, 0x5C, 0xA1, 0x6C, 0xFF, 0x76, 0x21, 0x68, 0x91, 0xA9, 0x67, 0x6A, 0xA3, 0x1A, 0xAA, 0x6C, 0x42 },
|
|
+ { 0xF5, 0x04, 0x1C, 0x24, 0x12, 0x70, 0xEB, 0x04, 0xC7, 0x1E, 0xC2, 0xC9, 0x5D, 0x4C, 0x38, 0xD8, 0x03, 0xB1, 0x23, 0x7B, 0x0F, 0x29, 0xFD, 0x4D, 0xB3, 0xEB, 0x39, 0x76, 0x69, 0xE8, 0x86, 0x99 },
|
|
+ { 0x9A, 0x4C, 0xE0, 0x77, 0xC3, 0x49, 0x32, 0x2F, 0x59, 0x5E, 0x0E, 0xE7, 0x9E, 0xD0, 0xDA, 0x5F, 0xAB, 0x66, 0x75, 0x2C, 0xBF, 0xEF, 0x8F, 0x87, 0xD0, 0xE9, 0xD0, 0x72, 0x3C, 0x75, 0x30, 0xDD },
|
|
+ { 0x65, 0x7B, 0x09, 0xF3, 0xD0, 0xF5, 0x2B, 0x5B, 0x8F, 0x2F, 0x97, 0x16, 0x3A, 0x0E, 0xDF, 0x0C, 0x04, 0xF0, 0x75, 0x40, 0x8A, 0x07, 0xBB, 0xEB, 0x3A, 0x41, 0x01, 0xA8, 0x91, 0x99, 0x0D, 0x62 },
|
|
+ { 0x1E, 0x3F, 0x7B, 0xD5, 0xA5, 0x8F, 0xA5, 0x33, 0x34, 0x4A, 0xA8, 0xED, 0x3A, 0xC1, 0x22, 0xBB, 0x9E, 0x70, 0xD4, 0xEF, 0x50, 0xD0, 0x04, 0x53, 0x08, 0x21, 0x94, 0x8F, 0x5F, 0xE6, 0x31, 0x5A },
|
|
+ { 0x80, 0xDC, 0xCF, 0x3F, 0xD8, 0x3D, 0xFD, 0x0D, 0x35, 0xAA, 0x28, 0x58, 0x59, 0x22, 0xAB, 0x89, 0xD5, 0x31, 0x39, 0x97, 0x67, 0x3E, 0xAF, 0x90, 0x5C, 0xEA, 0x9C, 0x0B, 0x22, 0x5C, 0x7B, 0x5F },
|
|
+ { 0x8A, 0x0D, 0x0F, 0xBF, 0x63, 0x77, 0xD8, 0x3B, 0xB0, 0x8B, 0x51, 0x4B, 0x4B, 0x1C, 0x43, 0xAC, 0xC9, 0x5D, 0x75, 0x17, 0x14, 0xF8, 0x92, 0x56, 0x45, 0xCB, 0x6B, 0xC8, 0x56, 0xCA, 0x15, 0x0A },
|
|
+ { 0x9F, 0xA5, 0xB4, 0x87, 0x73, 0x8A, 0xD2, 0x84, 0x4C, 0xC6, 0x34, 0x8A, 0x90, 0x19, 0x18, 0xF6, 0x59, 0xA3, 0xB8, 0x9E, 0x9C, 0x0D, 0xFE, 0xEA, 0xD3, 0x0D, 0xD9, 0x4B, 0xCF, 0x42, 0xEF, 0x8E },
|
|
+ { 0x80, 0x83, 0x2C, 0x4A, 0x16, 0x77, 0xF5, 0xEA, 0x25, 0x60, 0xF6, 0x68, 0xE9, 0x35, 0x4D, 0xD3, 0x69, 0x97, 0xF0, 0x37, 0x28, 0xCF, 0xA5, 0x5E, 0x1B, 0x38, 0x33, 0x7C, 0x0C, 0x9E, 0xF8, 0x18 },
|
|
+ { 0xAB, 0x37, 0xDD, 0xB6, 0x83, 0x13, 0x7E, 0x74, 0x08, 0x0D, 0x02, 0x6B, 0x59, 0x0B, 0x96, 0xAE, 0x9B, 0xB4, 0x47, 0x72, 0x2F, 0x30, 0x5A, 0x5A, 0xC5, 0x70, 0xEC, 0x1D, 0xF9, 0xB1, 0x74, 0x3C },
|
|
+ { 0x3E, 0xE7, 0x35, 0xA6, 0x94, 0xC2, 0x55, 0x9B, 0x69, 0x3A, 0xA6, 0x86, 0x29, 0x36, 0x1E, 0x15, 0xD1, 0x22, 0x65, 0xAD, 0x6A, 0x3D, 0xED, 0xF4, 0x88, 0xB0, 0xB0, 0x0F, 0xAC, 0x97, 0x54, 0xBA },
|
|
+ { 0xD6, 0xFC, 0xD2, 0x32, 0x19, 0xB6, 0x47, 0xE4, 0xCB, 0xD5, 0xEB, 0x2D, 0x0A, 0xD0, 0x1E, 0xC8, 0x83, 0x8A, 0x4B, 0x29, 0x01, 0xFC, 0x32, 0x5C, 0xC3, 0x70, 0x19, 0x81, 0xCA, 0x6C, 0x88, 0x8B },
|
|
+ { 0x05, 0x20, 0xEC, 0x2F, 0x5B, 0xF7, 0xA7, 0x55, 0xDA, 0xCB, 0x50, 0xC6, 0xBF, 0x23, 0x3E, 0x35, 0x15, 0x43, 0x47, 0x63, 0xDB, 0x01, 0x39, 0xCC, 0xD9, 0xFA, 0xEF, 0xBB, 0x82, 0x07, 0x61, 0x2D },
|
|
+ { 0xAF, 0xF3, 0xB7, 0x5F, 0x3F, 0x58, 0x12, 0x64, 0xD7, 0x66, 0x16, 0x62, 0xB9, 0x2F, 0x5A, 0xD3, 0x7C, 0x1D, 0x32, 0xBD, 0x45, 0xFF, 0x81, 0xA4, 0xED, 0x8A, 0xDC, 0x9E, 0xF3, 0x0D, 0xD9, 0x89 },
|
|
+ { 0xD0, 0xDD, 0x65, 0x0B, 0xEF, 0xD3, 0xBA, 0x63, 0xDC, 0x25, 0x10, 0x2C, 0x62, 0x7C, 0x92, 0x1B, 0x9C, 0xBE, 0xB0, 0xB1, 0x30, 0x68, 0x69, 0x35, 0xB5, 0xC9, 0x27, 0xCB, 0x7C, 0xCD, 0x5E, 0x3B },
|
|
+ { 0xE1, 0x14, 0x98, 0x16, 0xB1, 0x0A, 0x85, 0x14, 0xFB, 0x3E, 0x2C, 0xAB, 0x2C, 0x08, 0xBE, 0xE9, 0xF7, 0x3C, 0xE7, 0x62, 0x21, 0x70, 0x12, 0x46, 0xA5, 0x89, 0xBB, 0xB6, 0x73, 0x02, 0xD8, 0xA9 },
|
|
+ { 0x7D, 0xA3, 0xF4, 0x41, 0xDE, 0x90, 0x54, 0x31, 0x7E, 0x72, 0xB5, 0xDB, 0xF9, 0x79, 0xDA, 0x01, 0xE6, 0xBC, 0xEE, 0xBB, 0x84, 0x78, 0xEA, 0xE6, 0xA2, 0x28, 0x49, 0xD9, 0x02, 0x92, 0x63, 0x5C },
|
|
+ { 0x12, 0x30, 0xB1, 0xFC, 0x8A, 0x7D, 0x92, 0x15, 0xED, 0xC2, 0xD4, 0xA2, 0xDE, 0xCB, 0xDD, 0x0A, 0x6E, 0x21, 0x6C, 0x92, 0x42, 0x78, 0xC9, 0x1F, 0xC5, 0xD1, 0x0E, 0x7D, 0x60, 0x19, 0x2D, 0x94 },
|
|
+ { 0x57, 0x50, 0xD7, 0x16, 0xB4, 0x80, 0x8F, 0x75, 0x1F, 0xEB, 0xC3, 0x88, 0x06, 0xBA, 0x17, 0x0B, 0xF6, 0xD5, 0x19, 0x9A, 0x78, 0x16, 0xBE, 0x51, 0x4E, 0x3F, 0x93, 0x2F, 0xBE, 0x0C, 0xB8, 0x71 },
|
|
+ { 0x6F, 0xC5, 0x9B, 0x2F, 0x10, 0xFE, 0xBA, 0x95, 0x4A, 0xA6, 0x82, 0x0B, 0x3C, 0xA9, 0x87, 0xEE, 0x81, 0xD5, 0xCC, 0x1D, 0xA3, 0xC6, 0x3C, 0xE8, 0x27, 0x30, 0x1C, 0x56, 0x9D, 0xFB, 0x39, 0xCE },
|
|
+ { 0xC7, 0xC3, 0xFE, 0x1E, 0xEB, 0xDC, 0x7B, 0x5A, 0x93, 0x93, 0x26, 0xE8, 0xDD, 0xB8, 0x3E, 0x8B, 0xF2, 0xB7, 0x80, 0xB6, 0x56, 0x78, 0xCB, 0x62, 0xF2, 0x08, 0xB0, 0x40, 0xAB, 0xDD, 0x35, 0xE2 },
|
|
+ { 0x0C, 0x75, 0xC1, 0xA1, 0x5C, 0xF3, 0x4A, 0x31, 0x4E, 0xE4, 0x78, 0xF4, 0xA5, 0xCE, 0x0B, 0x8A, 0x6B, 0x36, 0x52, 0x8E, 0xF7, 0xA8, 0x20, 0x69, 0x6C, 0x3E, 0x42, 0x46, 0xC5, 0xA1, 0x58, 0x64 },
|
|
+ { 0x21, 0x6D, 0xC1, 0x2A, 0x10, 0x85, 0x69, 0xA3, 0xC7, 0xCD, 0xDE, 0x4A, 0xED, 0x43, 0xA6, 0xC3, 0x30, 0x13, 0x9D, 0xDA, 0x3C, 0xCC, 0x4A, 0x10, 0x89, 0x05, 0xDB, 0x38, 0x61, 0x89, 0x90, 0x50 },
|
|
+ { 0xA5, 0x7B, 0xE6, 0xAE, 0x67, 0x56, 0xF2, 0x8B, 0x02, 0xF5, 0x9D, 0xAD, 0xF7, 0xE0, 0xD7, 0xD8, 0x80, 0x7F, 0x10, 0xFA, 0x15, 0xCE, 0xD1, 0xAD, 0x35, 0x85, 0x52, 0x1A, 0x1D, 0x99, 0x5A, 0x89 },
|
|
+ { 0x81, 0x6A, 0xEF, 0x87, 0x59, 0x53, 0x71, 0x6C, 0xD7, 0xA5, 0x81, 0xF7, 0x32, 0xF5, 0x3D, 0xD4, 0x35, 0xDA, 0xB6, 0x6D, 0x09, 0xC3, 0x61, 0xD2, 0xD6, 0x59, 0x2D, 0xE1, 0x77, 0x55, 0xD8, 0xA8 },
|
|
+ { 0x9A, 0x76, 0x89, 0x32, 0x26, 0x69, 0x3B, 0x6E, 0xA9, 0x7E, 0x6A, 0x73, 0x8F, 0x9D, 0x10, 0xFB, 0x3D, 0x0B, 0x43, 0xAE, 0x0E, 0x8B, 0x7D, 0x81, 0x23, 0xEA, 0x76, 0xCE, 0x97, 0x98, 0x9C, 0x7E },
|
|
+ { 0x8D, 0xAE, 0xDB, 0x9A, 0x27, 0x15, 0x29, 0xDB, 0xB7, 0xDC, 0x3B, 0x60, 0x7F, 0xE5, 0xEB, 0x2D, 0x32, 0x11, 0x77, 0x07, 0x58, 0xDD, 0x3B, 0x0A, 0x35, 0x93, 0xD2, 0xD7, 0x95, 0x4E, 0x2D, 0x5B },
|
|
+ { 0x16, 0xDB, 0xC0, 0xAA, 0x5D, 0xD2, 0xC7, 0x74, 0xF5, 0x05, 0x10, 0x0F, 0x73, 0x37, 0x86, 0xD8, 0xA1, 0x75, 0xFC, 0xBB, 0xB5, 0x9C, 0x43, 0xE1, 0xFB, 0xFF, 0x3E, 0x1E, 0xAF, 0x31, 0xCB, 0x4A },
|
|
+ { 0x86, 0x06, 0xCB, 0x89, 0x9C, 0x6A, 0xEA, 0xF5, 0x1B, 0x9D, 0xB0, 0xFE, 0x49, 0x24, 0xA9, 0xFD, 0x5D, 0xAB, 0xC1, 0x9F, 0x88, 0x26, 0xF2, 0xBC, 0x1C, 0x1D, 0x7D, 0xA1, 0x4D, 0x2C, 0x2C, 0x99 },
|
|
+ { 0x84, 0x79, 0x73, 0x1A, 0xED, 0xA5, 0x7B, 0xD3, 0x7E, 0xAD, 0xB5, 0x1A, 0x50, 0x7E, 0x30, 0x7F, 0x3B, 0xD9, 0x5E, 0x69, 0xDB, 0xCA, 0x94, 0xF3, 0xBC, 0x21, 0x72, 0x60, 0x66, 0xAD, 0x6D, 0xFD },
|
|
+ { 0x58, 0x47, 0x3A, 0x9E, 0xA8, 0x2E, 0xFA, 0x3F, 0x3B, 0x3D, 0x8F, 0xC8, 0x3E, 0xD8, 0x86, 0x31, 0x27, 0xB3, 0x3A, 0xE8, 0xDE, 0xAE, 0x63, 0x07, 0x20, 0x1E, 0xDB, 0x6D, 0xDE, 0x61, 0xDE, 0x29 },
|
|
+ { 0x9A, 0x92, 0x55, 0xD5, 0x3A, 0xF1, 0x16, 0xDE, 0x8B, 0xA2, 0x7C, 0xE3, 0x5B, 0x4C, 0x7E, 0x15, 0x64, 0x06, 0x57, 0xA0, 0xFC, 0xB8, 0x88, 0xC7, 0x0D, 0x95, 0x43, 0x1D, 0xAC, 0xD8, 0xF8, 0x30 },
|
|
+ { 0x9E, 0xB0, 0x5F, 0xFB, 0xA3, 0x9F, 0xD8, 0x59, 0x6A, 0x45, 0x49, 0x3E, 0x18, 0xD2, 0x51, 0x0B, 0xF3, 0xEF, 0x06, 0x5C, 0x51, 0xD6, 0xE1, 0x3A, 0xBE, 0x66, 0xAA, 0x57, 0xE0, 0x5C, 0xFD, 0xB7 },
|
|
+ { 0x81, 0xDC, 0xC3, 0xA5, 0x05, 0xEA, 0xCE, 0x3F, 0x87, 0x9D, 0x8F, 0x70, 0x27, 0x76, 0x77, 0x0F, 0x9D, 0xF5, 0x0E, 0x52, 0x1D, 0x14, 0x28, 0xA8, 0x5D, 0xAF, 0x04, 0xF9, 0xAD, 0x21, 0x50, 0xE0 },
|
|
+ { 0xE3, 0xE3, 0xC4, 0xAA, 0x3A, 0xCB, 0xBC, 0x85, 0x33, 0x2A, 0xF9, 0xD5, 0x64, 0xBC, 0x24, 0x16, 0x5E, 0x16, 0x87, 0xF6, 0xB1, 0xAD, 0xCB, 0xFA, 0xE7, 0x7A, 0x8F, 0x03, 0xC7, 0x2A, 0xC2, 0x8C },
|
|
+ { 0x67, 0x46, 0xC8, 0x0B, 0x4E, 0xB5, 0x6A, 0xEA, 0x45, 0xE6, 0x4E, 0x72, 0x89, 0xBB, 0xA3, 0xED, 0xBF, 0x45, 0xEC, 0xF8, 0x20, 0x64, 0x81, 0xFF, 0x63, 0x02, 0x12, 0x29, 0x84, 0xCD, 0x52, 0x6A },
|
|
+ { 0x2B, 0x62, 0x8E, 0x52, 0x76, 0x4D, 0x7D, 0x62, 0xC0, 0x86, 0x8B, 0x21, 0x23, 0x57, 0xCD, 0xD1, 0x2D, 0x91, 0x49, 0x82, 0x2F, 0x4E, 0x98, 0x45, 0xD9, 0x18, 0xA0, 0x8D, 0x1A, 0xE9, 0x90, 0xC0 },
|
|
+ { 0xE4, 0xBF, 0xE8, 0x0D, 0x58, 0xC9, 0x19, 0x94, 0x61, 0x39, 0x09, 0xDC, 0x4B, 0x1A, 0x12, 0x49, 0x68, 0x96, 0xC0, 0x04, 0xAF, 0x7B, 0x57, 0x01, 0x48, 0x3D, 0xE4, 0x5D, 0x28, 0x23, 0xD7, 0x8E },
|
|
+ { 0xEB, 0xB4, 0xBA, 0x15, 0x0C, 0xEF, 0x27, 0x34, 0x34, 0x5B, 0x5D, 0x64, 0x1B, 0xBE, 0xD0, 0x3A, 0x21, 0xEA, 0xFA, 0xE9, 0x33, 0xC9, 0x9E, 0x00, 0x92, 0x12, 0xEF, 0x04, 0x57, 0x4A, 0x85, 0x30 },
|
|
+ { 0x39, 0x66, 0xEC, 0x73, 0xB1, 0x54, 0xAC, 0xC6, 0x97, 0xAC, 0x5C, 0xF5, 0xB2, 0x4B, 0x40, 0xBD, 0xB0, 0xDB, 0x9E, 0x39, 0x88, 0x36, 0xD7, 0x6D, 0x4B, 0x88, 0x0E, 0x3B, 0x2A, 0xF1, 0xAA, 0x27 },
|
|
+ { 0xEF, 0x7E, 0x48, 0x31, 0xB3, 0xA8, 0x46, 0x36, 0x51, 0x8D, 0x6E, 0x4B, 0xFC, 0xE6, 0x4A, 0x43, 0xDB, 0x2A, 0x5D, 0xDA, 0x9C, 0xCA, 0x2B, 0x44, 0xF3, 0x90, 0x33, 0xBD, 0xC4, 0x0D, 0x62, 0x43 },
|
|
+ { 0x7A, 0xBF, 0x6A, 0xCF, 0x5C, 0x8E, 0x54, 0x9D, 0xDB, 0xB1, 0x5A, 0xE8, 0xD8, 0xB3, 0x88, 0xC1, 0xC1, 0x97, 0xE6, 0x98, 0x73, 0x7C, 0x97, 0x85, 0x50, 0x1E, 0xD1, 0xF9, 0x49, 0x30, 0xB7, 0xD9 },
|
|
+ { 0x88, 0x01, 0x8D, 0xED, 0x66, 0x81, 0x3F, 0x0C, 0xA9, 0x5D, 0xEF, 0x47, 0x4C, 0x63, 0x06, 0x92, 0x01, 0x99, 0x67, 0xB9, 0xE3, 0x68, 0x88, 0xDA, 0xDD, 0x94, 0x12, 0x47, 0x19, 0xB6, 0x82, 0xF6 },
|
|
+ { 0x39, 0x30, 0x87, 0x6B, 0x9F, 0xC7, 0x52, 0x90, 0x36, 0xB0, 0x08, 0xB1, 0xB8, 0xBB, 0x99, 0x75, 0x22, 0xA4, 0x41, 0x63, 0x5A, 0x0C, 0x25, 0xEC, 0x02, 0xFB, 0x6D, 0x90, 0x26, 0xE5, 0x5A, 0x97 },
|
|
+ { 0x0A, 0x40, 0x49, 0xD5, 0x7E, 0x83, 0x3B, 0x56, 0x95, 0xFA, 0xC9, 0x3D, 0xD1, 0xFB, 0xEF, 0x31, 0x66, 0xB4, 0x4B, 0x12, 0xAD, 0x11, 0x24, 0x86, 0x62, 0x38, 0x3A, 0xE0, 0x51, 0xE1, 0x58, 0x27 },
|
|
+ { 0x81, 0xDC, 0xC0, 0x67, 0x8B, 0xB6, 0xA7, 0x65, 0xE4, 0x8C, 0x32, 0x09, 0x65, 0x4F, 0xE9, 0x00, 0x89, 0xCE, 0x44, 0xFF, 0x56, 0x18, 0x47, 0x7E, 0x39, 0xAB, 0x28, 0x64, 0x76, 0xDF, 0x05, 0x2B },
|
|
+ { 0xE6, 0x9B, 0x3A, 0x36, 0xA4, 0x46, 0x19, 0x12, 0xDC, 0x08, 0x34, 0x6B, 0x11, 0xDD, 0xCB, 0x9D, 0xB7, 0x96, 0xF8, 0x85, 0xFD, 0x01, 0x93, 0x6E, 0x66, 0x2F, 0xE2, 0x92, 0x97, 0xB0, 0x99, 0xA4 },
|
|
+ { 0x5A, 0xC6, 0x50, 0x3B, 0x0D, 0x8D, 0xA6, 0x91, 0x76, 0x46, 0xE6, 0xDC, 0xC8, 0x7E, 0xDC, 0x58, 0xE9, 0x42, 0x45, 0x32, 0x4C, 0xC2, 0x04, 0xF4, 0xDD, 0x4A, 0xF0, 0x15, 0x63, 0xAC, 0xD4, 0x27 },
|
|
+ { 0xDF, 0x6D, 0xDA, 0x21, 0x35, 0x9A, 0x30, 0xBC, 0x27, 0x17, 0x80, 0x97, 0x1C, 0x1A, 0xBD, 0x56, 0xA6, 0xEF, 0x16, 0x7E, 0x48, 0x08, 0x87, 0x88, 0x8E, 0x73, 0xA8, 0x6D, 0x3B, 0xF6, 0x05, 0xE9 },
|
|
+ { 0xE8, 0xE6, 0xE4, 0x70, 0x71, 0xE7, 0xB7, 0xDF, 0x25, 0x80, 0xF2, 0x25, 0xCF, 0xBB, 0xED, 0xF8, 0x4C, 0xE6, 0x77, 0x46, 0x62, 0x66, 0x28, 0xD3, 0x30, 0x97, 0xE4, 0xB7, 0xDC, 0x57, 0x11, 0x07 },
|
|
+ { 0x53, 0xE4, 0x0E, 0xAD, 0x62, 0x05, 0x1E, 0x19, 0xCB, 0x9B, 0xA8, 0x13, 0x3E, 0x3E, 0x5C, 0x1C, 0xE0, 0x0D, 0xDC, 0xAD, 0x8A, 0xCF, 0x34, 0x2A, 0x22, 0x43, 0x60, 0xB0, 0xAC, 0xC1, 0x47, 0x77 },
|
|
+ { 0x9C, 0xCD, 0x53, 0xFE, 0x80, 0xBE, 0x78, 0x6A, 0xA9, 0x84, 0x63, 0x84, 0x62, 0xFB, 0x28, 0xAF, 0xDF, 0x12, 0x2B, 0x34, 0xD7, 0x8F, 0x46, 0x87, 0xEC, 0x63, 0x2B, 0xB1, 0x9D, 0xE2, 0x37, 0x1A },
|
|
+ { 0xCB, 0xD4, 0x80, 0x52, 0xC4, 0x8D, 0x78, 0x84, 0x66, 0xA3, 0xE8, 0x11, 0x8C, 0x56, 0xC9, 0x7F, 0xE1, 0x46, 0xE5, 0x54, 0x6F, 0xAA, 0xF9, 0x3E, 0x2B, 0xC3, 0xC4, 0x7E, 0x45, 0x93, 0x97, 0x53 },
|
|
+ { 0x25, 0x68, 0x83, 0xB1, 0x4E, 0x2A, 0xF4, 0x4D, 0xAD, 0xB2, 0x8E, 0x1B, 0x34, 0xB2, 0xAC, 0x0F, 0x0F, 0x4C, 0x91, 0xC3, 0x4E, 0xC9, 0x16, 0x9E, 0x29, 0x03, 0x61, 0x58, 0xAC, 0xAA, 0x95, 0xB9 },
|
|
+ { 0x44, 0x71, 0xB9, 0x1A, 0xB4, 0x2D, 0xB7, 0xC4, 0xDD, 0x84, 0x90, 0xAB, 0x95, 0xA2, 0xEE, 0x8D, 0x04, 0xE3, 0xEF, 0x5C, 0x3D, 0x6F, 0xC7, 0x1A, 0xC7, 0x4B, 0x2B, 0x26, 0x91, 0x4D, 0x16, 0x41 },
|
|
+ { 0xA5, 0xEB, 0x08, 0x03, 0x8F, 0x8F, 0x11, 0x55, 0xED, 0x86, 0xE6, 0x31, 0x90, 0x6F, 0xC1, 0x30, 0x95, 0xF6, 0xBB, 0xA4, 0x1D, 0xE5, 0xD4, 0xE7, 0x95, 0x75, 0x8E, 0xC8, 0xC8, 0xDF, 0x8A, 0xF1 },
|
|
+ { 0xDC, 0x1D, 0xB6, 0x4E, 0xD8, 0xB4, 0x8A, 0x91, 0x0E, 0x06, 0x0A, 0x6B, 0x86, 0x63, 0x74, 0xC5, 0x78, 0x78, 0x4E, 0x9A, 0xC4, 0x9A, 0xB2, 0x77, 0x40, 0x92, 0xAC, 0x71, 0x50, 0x19, 0x34, 0xAC },
|
|
+ { 0x28, 0x54, 0x13, 0xB2, 0xF2, 0xEE, 0x87, 0x3D, 0x34, 0x31, 0x9E, 0xE0, 0xBB, 0xFB, 0xB9, 0x0F, 0x32, 0xDA, 0x43, 0x4C, 0xC8, 0x7E, 0x3D, 0xB5, 0xED, 0x12, 0x1B, 0xB3, 0x98, 0xED, 0x96, 0x4B },
|
|
+ { 0x02, 0x16, 0xE0, 0xF8, 0x1F, 0x75, 0x0F, 0x26, 0xF1, 0x99, 0x8B, 0xC3, 0x93, 0x4E, 0x3E, 0x12, 0x4C, 0x99, 0x45, 0xE6, 0x85, 0xA6, 0x0B, 0x25, 0xE8, 0xFB, 0xD9, 0x62, 0x5A, 0xB6, 0xB5, 0x99 },
|
|
+ { 0x38, 0xC4, 0x10, 0xF5, 0xB9, 0xD4, 0x07, 0x20, 0x50, 0x75, 0x5B, 0x31, 0xDC, 0xA8, 0x9F, 0xD5, 0x39, 0x5C, 0x67, 0x85, 0xEE, 0xB3, 0xD7, 0x90, 0xF3, 0x20, 0xFF, 0x94, 0x1C, 0x5A, 0x93, 0xBF },
|
|
+ { 0xF1, 0x84, 0x17, 0xB3, 0x9D, 0x61, 0x7A, 0xB1, 0xC1, 0x8F, 0xDF, 0x91, 0xEB, 0xD0, 0xFC, 0x6D, 0x55, 0x16, 0xBB, 0x34, 0xCF, 0x39, 0x36, 0x40, 0x37, 0xBC, 0xE8, 0x1F, 0xA0, 0x4C, 0xEC, 0xB1 },
|
|
+ { 0x1F, 0xA8, 0x77, 0xDE, 0x67, 0x25, 0x9D, 0x19, 0x86, 0x3A, 0x2A, 0x34, 0xBC, 0xC6, 0x96, 0x2A, 0x2B, 0x25, 0xFC, 0xBF, 0x5C, 0xBE, 0xCD, 0x7E, 0xDE, 0x8F, 0x1F, 0xA3, 0x66, 0x88, 0xA7, 0x96 },
|
|
+ { 0x5B, 0xD1, 0x69, 0xE6, 0x7C, 0x82, 0xC2, 0xC2, 0xE9, 0x8E, 0xF7, 0x00, 0x8B, 0xDF, 0x26, 0x1F, 0x2D, 0xDF, 0x30, 0xB1, 0xC0, 0x0F, 0x9E, 0x7F, 0x27, 0x5B, 0xB3, 0xE8, 0xA2, 0x8D, 0xC9, 0xA2 },
|
|
+ { 0xC8, 0x0A, 0xBE, 0xEB, 0xB6, 0x69, 0xAD, 0x5D, 0xEE, 0xB5, 0xF5, 0xEC, 0x8E, 0xA6, 0xB7, 0xA0, 0x5D, 0xDF, 0x7D, 0x31, 0xEC, 0x4C, 0x0A, 0x2E, 0xE2, 0x0B, 0x0B, 0x98, 0xCA, 0xEC, 0x67, 0x46 },
|
|
+ { 0xE7, 0x6D, 0x3F, 0xBD, 0xA5, 0xBA, 0x37, 0x4E, 0x6B, 0xF8, 0xE5, 0x0F, 0xAD, 0xC3, 0xBB, 0xB9, 0xBA, 0x5C, 0x20, 0x6E, 0xBD, 0xEC, 0x89, 0xA3, 0xA5, 0x4C, 0xF3, 0xDD, 0x84, 0xA0, 0x70, 0x16 },
|
|
+ { 0x7B, 0xBA, 0x9D, 0xC5, 0xB5, 0xDB, 0x20, 0x71, 0xD1, 0x77, 0x52, 0xB1, 0x04, 0x4C, 0x1E, 0xCE, 0xD9, 0x6A, 0xAF, 0x2D, 0xD4, 0x6E, 0x9B, 0x43, 0x37, 0x50, 0xE8, 0xEA, 0x0D, 0xCC, 0x18, 0x70 },
|
|
+ { 0xF2, 0x9B, 0x1B, 0x1A, 0xB9, 0xBA, 0xB1, 0x63, 0x01, 0x8E, 0xE3, 0xDA, 0x15, 0x23, 0x2C, 0xCA, 0x78, 0xEC, 0x52, 0xDB, 0xC3, 0x4E, 0xDA, 0x5B, 0x82, 0x2E, 0xC1, 0xD8, 0x0F, 0xC2, 0x1B, 0xD0 },
|
|
+ { 0x9E, 0xE3, 0xE3, 0xE7, 0xE9, 0x00, 0xF1, 0xE1, 0x1D, 0x30, 0x8C, 0x4B, 0x2B, 0x30, 0x76, 0xD2, 0x72, 0xCF, 0x70, 0x12, 0x4F, 0x9F, 0x51, 0xE1, 0xDA, 0x60, 0xF3, 0x78, 0x46, 0xCD, 0xD2, 0xF4 },
|
|
+ { 0x70, 0xEA, 0x3B, 0x01, 0x76, 0x92, 0x7D, 0x90, 0x96, 0xA1, 0x85, 0x08, 0xCD, 0x12, 0x3A, 0x29, 0x03, 0x25, 0x92, 0x0A, 0x9D, 0x00, 0xA8, 0x9B, 0x5D, 0xE0, 0x42, 0x73, 0xFB, 0xC7, 0x6B, 0x85 },
|
|
+ { 0x67, 0xDE, 0x25, 0xC0, 0x2A, 0x4A, 0xAB, 0xA2, 0x3B, 0xDC, 0x97, 0x3C, 0x8B, 0xB0, 0xB5, 0x79, 0x6D, 0x47, 0xCC, 0x06, 0x59, 0xD4, 0x3D, 0xFF, 0x1F, 0x97, 0xDE, 0x17, 0x49, 0x63, 0xB6, 0x8E },
|
|
+ { 0xB2, 0x16, 0x8E, 0x4E, 0x0F, 0x18, 0xB0, 0xE6, 0x41, 0x00, 0xB5, 0x17, 0xED, 0x95, 0x25, 0x7D, 0x73, 0xF0, 0x62, 0x0D, 0xF8, 0x85, 0xC1, 0x3D, 0x2E, 0xCF, 0x79, 0x36, 0x7B, 0x38, 0x4C, 0xEE },
|
|
+ { 0x2E, 0x7D, 0xEC, 0x24, 0x28, 0x85, 0x3B, 0x2C, 0x71, 0x76, 0x07, 0x45, 0x54, 0x1F, 0x7A, 0xFE, 0x98, 0x25, 0xB5, 0xDD, 0x77, 0xDF, 0x06, 0x51, 0x1D, 0x84, 0x41, 0xA9, 0x4B, 0xAC, 0xC9, 0x27 },
|
|
+ { 0xCA, 0x9F, 0xFA, 0xC4, 0xC4, 0x3F, 0x0B, 0x48, 0x46, 0x1D, 0xC5, 0xC2, 0x63, 0xBE, 0xA3, 0xF6, 0xF0, 0x06, 0x11, 0xCE, 0xAC, 0xAB, 0xF6, 0xF8, 0x95, 0xBA, 0x2B, 0x01, 0x01, 0xDB, 0xB6, 0x8D },
|
|
+ { 0x74, 0x10, 0xD4, 0x2D, 0x8F, 0xD1, 0xD5, 0xE9, 0xD2, 0xF5, 0x81, 0x5C, 0xB9, 0x34, 0x17, 0x99, 0x88, 0x28, 0xEF, 0x3C, 0x42, 0x30, 0xBF, 0xBD, 0x41, 0x2D, 0xF0, 0xA4, 0xA7, 0xA2, 0x50, 0x7A },
|
|
+ { 0x50, 0x10, 0xF6, 0x84, 0x51, 0x6D, 0xCC, 0xD0, 0xB6, 0xEE, 0x08, 0x52, 0xC2, 0x51, 0x2B, 0x4D, 0xC0, 0x06, 0x6C, 0xF0, 0xD5, 0x6F, 0x35, 0x30, 0x29, 0x78, 0xDB, 0x8A, 0xE3, 0x2C, 0x6A, 0x81 },
|
|
+ { 0xAC, 0xAA, 0xB5, 0x85, 0xF7, 0xB7, 0x9B, 0x71, 0x99, 0x35, 0xCE, 0xB8, 0x95, 0x23, 0xDD, 0xC5, 0x48, 0x27, 0xF7, 0x5C, 0x56, 0x88, 0x38, 0x56, 0x15, 0x4A, 0x56, 0xCD, 0xCD, 0x5E, 0xE9, 0x88 },
|
|
+ { 0x66, 0x6D, 0xE5, 0xD1, 0x44, 0x0F, 0xEE, 0x73, 0x31, 0xAA, 0xF0, 0x12, 0x3A, 0x62, 0xEF, 0x2D, 0x8B, 0xA5, 0x74, 0x53, 0xA0, 0x76, 0x96, 0x35, 0xAC, 0x6C, 0xD0, 0x1E, 0x63, 0x3F, 0x77, 0x12 },
|
|
+ { 0xA6, 0xF9, 0x86, 0x58, 0xF6, 0xEA, 0xBA, 0xF9, 0x02, 0xD8, 0xB3, 0x87, 0x1A, 0x4B, 0x10, 0x1D, 0x16, 0x19, 0x6E, 0x8A, 0x4B, 0x24, 0x1E, 0x15, 0x58, 0xFE, 0x29, 0x96, 0x6E, 0x10, 0x3E, 0x8D },
|
|
+ { 0x89, 0x15, 0x46, 0xA8, 0xB2, 0x9F, 0x30, 0x47, 0xDD, 0xCF, 0xE5, 0xB0, 0x0E, 0x45, 0xFD, 0x55, 0x75, 0x63, 0x73, 0x10, 0x5E, 0xA8, 0x63, 0x7D, 0xFC, 0xFF, 0x54, 0x7B, 0x6E, 0xA9, 0x53, 0x5F },
|
|
+ { 0x18, 0xDF, 0xBC, 0x1A, 0xC5, 0xD2, 0x5B, 0x07, 0x61, 0x13, 0x7D, 0xBD, 0x22, 0xC1, 0x7C, 0x82, 0x9D, 0x0F, 0x0E, 0xF1, 0xD8, 0x23, 0x44, 0xE9, 0xC8, 0x9C, 0x28, 0x66, 0x94, 0xDA, 0x24, 0xE8 },
|
|
+ { 0xB5, 0x4B, 0x9B, 0x67, 0xF8, 0xFE, 0xD5, 0x4B, 0xBF, 0x5A, 0x26, 0x66, 0xDB, 0xDF, 0x4B, 0x23, 0xCF, 0xF1, 0xD1, 0xB6, 0xF4, 0xAF, 0xC9, 0x85, 0xB2, 0xE6, 0xD3, 0x30, 0x5A, 0x9F, 0xF8, 0x0F },
|
|
+ { 0x7D, 0xB4, 0x42, 0xE1, 0x32, 0xBA, 0x59, 0xBC, 0x12, 0x89, 0xAA, 0x98, 0xB0, 0xD3, 0xE8, 0x06, 0x00, 0x4F, 0x8E, 0xC1, 0x28, 0x11, 0xAF, 0x1E, 0x2E, 0x33, 0xC6, 0x9B, 0xFD, 0xE7, 0x29, 0xE1 },
|
|
+ { 0x25, 0x0F, 0x37, 0xCD, 0xC1, 0x5E, 0x81, 0x7D, 0x2F, 0x16, 0x0D, 0x99, 0x56, 0xC7, 0x1F, 0xE3, 0xEB, 0x5D, 0xB7, 0x45, 0x56, 0xE4, 0xAD, 0xF9, 0xA4, 0xFF, 0xAF, 0xBA, 0x74, 0x01, 0x03, 0x96 },
|
|
+ { 0x4A, 0xB8, 0xA3, 0xDD, 0x1D, 0xDF, 0x8A, 0xD4, 0x3D, 0xAB, 0x13, 0xA2, 0x7F, 0x66, 0xA6, 0x54, 0x4F, 0x29, 0x05, 0x97, 0xFA, 0x96, 0x04, 0x0E, 0x0E, 0x1D, 0xB9, 0x26, 0x3A, 0xA4, 0x79, 0xF8 },
|
|
+ { 0xEE, 0x61, 0x72, 0x7A, 0x07, 0x66, 0xDF, 0x93, 0x9C, 0xCD, 0xC8, 0x60, 0x33, 0x40, 0x44, 0xC7, 0x9A, 0x3C, 0x9B, 0x15, 0x62, 0x00, 0xBC, 0x3A, 0xA3, 0x29, 0x73, 0x48, 0x3D, 0x83, 0x41, 0xAE },
|
|
+ { 0x3F, 0x68, 0xC7, 0xEC, 0x63, 0xAC, 0x11, 0xEB, 0xB9, 0x8F, 0x94, 0xB3, 0x39, 0xB0, 0x5C, 0x10, 0x49, 0x84, 0xFD, 0xA5, 0x01, 0x03, 0x06, 0x01, 0x44, 0xE5, 0xA2, 0xBF, 0xCC, 0xC9, 0xDA, 0x95 },
|
|
+ { 0x05, 0x6F, 0x29, 0x81, 0x6B, 0x8A, 0xF8, 0xF5, 0x66, 0x82, 0xBC, 0x4D, 0x7C, 0xF0, 0x94, 0x11, 0x1D, 0xA7, 0x73, 0x3E, 0x72, 0x6C, 0xD1, 0x3D, 0x6B, 0x3E, 0x8E, 0xA0, 0x3E, 0x92, 0xA0, 0xD5 },
|
|
+ { 0xF5, 0xEC, 0x43, 0xA2, 0x8A, 0xCB, 0xEF, 0xF1, 0xF3, 0x31, 0x8A, 0x5B, 0xCA, 0xC7, 0xC6, 0x6D, 0xDB, 0x52, 0x30, 0xB7, 0x9D, 0xB2, 0xD1, 0x05, 0xBC, 0xBE, 0x15, 0xF3, 0xC1, 0x14, 0x8D, 0x69 },
|
|
+ { 0x2A, 0x69, 0x60, 0xAD, 0x1D, 0x8D, 0xD5, 0x47, 0x55, 0x5C, 0xFB, 0xD5, 0xE4, 0x60, 0x0F, 0x1E, 0xAA, 0x1C, 0x8E, 0xDA, 0x34, 0xDE, 0x03, 0x74, 0xEC, 0x4A, 0x26, 0xEA, 0xAA, 0xA3, 0x3B, 0x4E },
|
|
+ { 0xDC, 0xC1, 0xEA, 0x7B, 0xAA, 0xB9, 0x33, 0x84, 0xF7, 0x6B, 0x79, 0x68, 0x66, 0x19, 0x97, 0x54, 0x74, 0x2F, 0x7B, 0x96, 0xD6, 0xB4, 0xC1, 0x20, 0x16, 0x5C, 0x04, 0xA6, 0xC4, 0xF5, 0xCE, 0x10 },
|
|
+ { 0x13, 0xD5, 0xDF, 0x17, 0x92, 0x21, 0x37, 0x9C, 0x6A, 0x78, 0xC0, 0x7C, 0x79, 0x3F, 0xF5, 0x34, 0x87, 0xCA, 0xE6, 0xBF, 0x9F, 0xE8, 0x82, 0x54, 0x1A, 0xB0, 0xE7, 0x35, 0xE3, 0xEA, 0xDA, 0x3B },
|
|
+ { 0x8C, 0x59, 0xE4, 0x40, 0x76, 0x41, 0xA0, 0x1E, 0x8F, 0xF9, 0x1F, 0x99, 0x80, 0xDC, 0x23, 0x6F, 0x4E, 0xCD, 0x6F, 0xCF, 0x52, 0x58, 0x9A, 0x09, 0x9A, 0x96, 0x16, 0x33, 0x96, 0x77, 0x14, 0xE1 },
|
|
+ { 0x83, 0x3B, 0x1A, 0xC6, 0xA2, 0x51, 0xFD, 0x08, 0xFD, 0x6D, 0x90, 0x8F, 0xEA, 0x2A, 0x4E, 0xE1, 0xE0, 0x40, 0xBC, 0xA9, 0x3F, 0xC1, 0xA3, 0x8E, 0xC3, 0x82, 0x0E, 0x0C, 0x10, 0xBD, 0x82, 0xEA },
|
|
+ { 0xA2, 0x44, 0xF9, 0x27, 0xF3, 0xB4, 0x0B, 0x8F, 0x6C, 0x39, 0x15, 0x70, 0xC7, 0x65, 0x41, 0x8F, 0x2F, 0x6E, 0x70, 0x8E, 0xAC, 0x90, 0x06, 0xC5, 0x1A, 0x7F, 0xEF, 0xF4, 0xAF, 0x3B, 0x2B, 0x9E },
|
|
+ { 0x3D, 0x99, 0xED, 0x95, 0x50, 0xCF, 0x11, 0x96, 0xE6, 0xC4, 0xD2, 0x0C, 0x25, 0x96, 0x20, 0xF8, 0x58, 0xC3, 0xD7, 0x03, 0x37, 0x4C, 0x12, 0x8C, 0xE7, 0xB5, 0x90, 0x31, 0x0C, 0x83, 0x04, 0x6D },
|
|
+ { 0x2B, 0x35, 0xC4, 0x7D, 0x7B, 0x87, 0x76, 0x1F, 0x0A, 0xE4, 0x3A, 0xC5, 0x6A, 0xC2, 0x7B, 0x9F, 0x25, 0x83, 0x03, 0x67, 0xB5, 0x95, 0xBE, 0x8C, 0x24, 0x0E, 0x94, 0x60, 0x0C, 0x6E, 0x33, 0x12 },
|
|
+ { 0x5D, 0x11, 0xED, 0x37, 0xD2, 0x4D, 0xC7, 0x67, 0x30, 0x5C, 0xB7, 0xE1, 0x46, 0x7D, 0x87, 0xC0, 0x65, 0xAC, 0x4B, 0xC8, 0xA4, 0x26, 0xDE, 0x38, 0x99, 0x1F, 0xF5, 0x9A, 0xA8, 0x73, 0x5D, 0x02 },
|
|
+ { 0xB8, 0x36, 0x47, 0x8E, 0x1C, 0xA0, 0x64, 0x0D, 0xCE, 0x6F, 0xD9, 0x10, 0xA5, 0x09, 0x62, 0x72, 0xC8, 0x33, 0x09, 0x90, 0xCD, 0x97, 0x86, 0x4A, 0xC2, 0xBF, 0x14, 0xEF, 0x6B, 0x23, 0x91, 0x4A },
|
|
+ { 0x91, 0x00, 0xF9, 0x46, 0xD6, 0xCC, 0xDE, 0x3A, 0x59, 0x7F, 0x90, 0xD3, 0x9F, 0xC1, 0x21, 0x5B, 0xAD, 0xDC, 0x74, 0x13, 0x64, 0x3D, 0x85, 0xC2, 0x1C, 0x3E, 0xEE, 0x5D, 0x2D, 0xD3, 0x28, 0x94 },
|
|
+ { 0xDA, 0x70, 0xEE, 0xDD, 0x23, 0xE6, 0x63, 0xAA, 0x1A, 0x74, 0xB9, 0x76, 0x69, 0x35, 0xB4, 0x79, 0x22, 0x2A, 0x72, 0xAF, 0xBA, 0x5C, 0x79, 0x51, 0x58, 0xDA, 0xD4, 0x1A, 0x3B, 0xD7, 0x7E, 0x40 },
|
|
+ { 0xF0, 0x67, 0xED, 0x6A, 0x0D, 0xBD, 0x43, 0xAA, 0x0A, 0x92, 0x54, 0xE6, 0x9F, 0xD6, 0x6B, 0xDD, 0x8A, 0xCB, 0x87, 0xDE, 0x93, 0x6C, 0x25, 0x8C, 0xFB, 0x02, 0x28, 0x5F, 0x2C, 0x11, 0xFA, 0x79 },
|
|
+ { 0x71, 0x5C, 0x99, 0xC7, 0xD5, 0x75, 0x80, 0xCF, 0x97, 0x53, 0xB4, 0xC1, 0xD7, 0x95, 0xE4, 0x5A, 0x83, 0xFB, 0xB2, 0x28, 0xC0, 0xD3, 0x6F, 0xBE, 0x20, 0xFA, 0xF3, 0x9B, 0xDD, 0x6D, 0x4E, 0x85 },
|
|
+ { 0xE4, 0x57, 0xD6, 0xAD, 0x1E, 0x67, 0xCB, 0x9B, 0xBD, 0x17, 0xCB, 0xD6, 0x98, 0xFA, 0x6D, 0x7D, 0xAE, 0x0C, 0x9B, 0x7A, 0xD6, 0xCB, 0xD6, 0x53, 0x96, 0x34, 0xE3, 0x2A, 0x71, 0x9C, 0x84, 0x92 },
|
|
+ { 0xEC, 0xE3, 0xEA, 0x81, 0x03, 0xE0, 0x24, 0x83, 0xC6, 0x4A, 0x70, 0xA4, 0xBD, 0xCE, 0xE8, 0xCE, 0xB6, 0x27, 0x8F, 0x25, 0x33, 0xF3, 0xF4, 0x8D, 0xBE, 0xED, 0xFB, 0xA9, 0x45, 0x31, 0xD4, 0xAE },
|
|
+ { 0x38, 0x8A, 0xA5, 0xD3, 0x66, 0x7A, 0x97, 0xC6, 0x8D, 0x3D, 0x56, 0xF8, 0xF3, 0xEE, 0x8D, 0x3D, 0x36, 0x09, 0x1F, 0x17, 0xFE, 0x5D, 0x1B, 0x0D, 0x5D, 0x84, 0xC9, 0x3B, 0x2F, 0xFE, 0x40, 0xBD },
|
|
+ { 0x8B, 0x6B, 0x31, 0xB9, 0xAD, 0x7C, 0x3D, 0x5C, 0xD8, 0x4B, 0xF9, 0x89, 0x47, 0xB9, 0xCD, 0xB5, 0x9D, 0xF8, 0xA2, 0x5F, 0xF7, 0x38, 0x10, 0x10, 0x13, 0xBE, 0x4F, 0xD6, 0x5E, 0x1D, 0xD1, 0xA3 },
|
|
+ { 0x06, 0x62, 0x91, 0xF6, 0xBB, 0xD2, 0x5F, 0x3C, 0x85, 0x3D, 0xB7, 0xD8, 0xB9, 0x5C, 0x9A, 0x1C, 0xFB, 0x9B, 0xF1, 0xC1, 0xC9, 0x9F, 0xB9, 0x5A, 0x9B, 0x78, 0x69, 0xD9, 0x0F, 0x1C, 0x29, 0x03 },
|
|
+ { 0xA7, 0x07, 0xEF, 0xBC, 0xCD, 0xCE, 0xED, 0x42, 0x96, 0x7A, 0x66, 0xF5, 0x53, 0x9B, 0x93, 0xED, 0x75, 0x60, 0xD4, 0x67, 0x30, 0x40, 0x16, 0xC4, 0x78, 0x0D, 0x77, 0x55, 0xA5, 0x65, 0xD4, 0xC4 },
|
|
+ { 0x38, 0xC5, 0x3D, 0xFB, 0x70, 0xBE, 0x7E, 0x79, 0x2B, 0x07, 0xA6, 0xA3, 0x5B, 0x8A, 0x6A, 0x0A, 0xBA, 0x02, 0xC5, 0xC5, 0xF3, 0x8B, 0xAF, 0x5C, 0x82, 0x3F, 0xDF, 0xD9, 0xE4, 0x2D, 0x65, 0x7E },
|
|
+ { 0xF2, 0x91, 0x13, 0x86, 0x50, 0x1D, 0x9A, 0xB9, 0xD7, 0x20, 0xCF, 0x8A, 0xD1, 0x05, 0x03, 0xD5, 0x63, 0x4B, 0xF4, 0xB7, 0xD1, 0x2B, 0x56, 0xDF, 0xB7, 0x4F, 0xEC, 0xC6, 0xE4, 0x09, 0x3F, 0x68 },
|
|
+ { 0xC6, 0xF2, 0xBD, 0xD5, 0x2B, 0x81, 0xE6, 0xE4, 0xF6, 0x59, 0x5A, 0xBD, 0x4D, 0x7F, 0xB3, 0x1F, 0x65, 0x11, 0x69, 0xD0, 0x0F, 0xF3, 0x26, 0x92, 0x6B, 0x34, 0x94, 0x7B, 0x28, 0xA8, 0x39, 0x59 },
|
|
+ { 0x29, 0x3D, 0x94, 0xB1, 0x8C, 0x98, 0xBB, 0x32, 0x23, 0x36, 0x6B, 0x8C, 0xE7, 0x4C, 0x28, 0xFB, 0xDF, 0x28, 0xE1, 0xF8, 0x4A, 0x33, 0x50, 0xB0, 0xEB, 0x2D, 0x18, 0x04, 0xA5, 0x77, 0x57, 0x9B },
|
|
+ { 0x2C, 0x2F, 0xA5, 0xC0, 0xB5, 0x15, 0x33, 0x16, 0x5B, 0xC3, 0x75, 0xC2, 0x2E, 0x27, 0x81, 0x76, 0x82, 0x70, 0xA3, 0x83, 0x98, 0x5D, 0x13, 0xBD, 0x6B, 0x67, 0xB6, 0xFD, 0x67, 0xF8, 0x89, 0xEB },
|
|
+ { 0xCA, 0xA0, 0x9B, 0x82, 0xB7, 0x25, 0x62, 0xE4, 0x3F, 0x4B, 0x22, 0x75, 0xC0, 0x91, 0x91, 0x8E, 0x62, 0x4D, 0x91, 0x16, 0x61, 0xCC, 0x81, 0x1B, 0xB5, 0xFA, 0xEC, 0x51, 0xF6, 0x08, 0x8E, 0xF7 },
|
|
+ { 0x24, 0x76, 0x1E, 0x45, 0xE6, 0x74, 0x39, 0x53, 0x79, 0xFB, 0x17, 0x72, 0x9C, 0x78, 0xCB, 0x93, 0x9E, 0x6F, 0x74, 0xC5, 0xDF, 0xFB, 0x9C, 0x96, 0x1F, 0x49, 0x59, 0x82, 0xC3, 0xED, 0x1F, 0xE3 },
|
|
+ { 0x55, 0xB7, 0x0A, 0x82, 0x13, 0x1E, 0xC9, 0x48, 0x88, 0xD7, 0xAB, 0x54, 0xA7, 0xC5, 0x15, 0x25, 0x5C, 0x39, 0x38, 0xBB, 0x10, 0xBC, 0x78, 0x4D, 0xC9, 0xB6, 0x7F, 0x07, 0x6E, 0x34, 0x1A, 0x73 },
|
|
+ { 0x6A, 0xB9, 0x05, 0x7B, 0x97, 0x7E, 0xBC, 0x3C, 0xA4, 0xD4, 0xCE, 0x74, 0x50, 0x6C, 0x25, 0xCC, 0xCD, 0xC5, 0x66, 0x49, 0x7C, 0x45, 0x0B, 0x54, 0x15, 0xA3, 0x94, 0x86, 0xF8, 0x65, 0x7A, 0x03 },
|
|
+ { 0x24, 0x06, 0x6D, 0xEE, 0xE0, 0xEC, 0xEE, 0x15, 0xA4, 0x5F, 0x0A, 0x32, 0x6D, 0x0F, 0x8D, 0xBC, 0x79, 0x76, 0x1E, 0xBB, 0x93, 0xCF, 0x8C, 0x03, 0x77, 0xAF, 0x44, 0x09, 0x78, 0xFC, 0xF9, 0x94 },
|
|
+ { 0x20, 0x00, 0x0D, 0x3F, 0x66, 0xBA, 0x76, 0x86, 0x0D, 0x5A, 0x95, 0x06, 0x88, 0xB9, 0xAA, 0x0D, 0x76, 0xCF, 0xEA, 0x59, 0xB0, 0x05, 0xD8, 0x59, 0x91, 0x4B, 0x1A, 0x46, 0x65, 0x3A, 0x93, 0x9B },
|
|
+ { 0xB9, 0x2D, 0xAA, 0x79, 0x60, 0x3E, 0x3B, 0xDB, 0xC3, 0xBF, 0xE0, 0xF4, 0x19, 0xE4, 0x09, 0xB2, 0xEA, 0x10, 0xDC, 0x43, 0x5B, 0xEE, 0xFE, 0x29, 0x59, 0xDA, 0x16, 0x89, 0x5D, 0x5D, 0xCA, 0x1C },
|
|
+ { 0xE9, 0x47, 0x94, 0x87, 0x05, 0xB2, 0x06, 0xD5, 0x72, 0xB0, 0xE8, 0xF6, 0x2F, 0x66, 0xA6, 0x55, 0x1C, 0xBD, 0x6B, 0xC3, 0x05, 0xD2, 0x6C, 0xE7, 0x53, 0x9A, 0x12, 0xF9, 0xAA, 0xDF, 0x75, 0x71 },
|
|
+ { 0x3D, 0x67, 0xC1, 0xB3, 0xF9, 0xB2, 0x39, 0x10, 0xE3, 0xD3, 0x5E, 0x6B, 0x0F, 0x2C, 0xCF, 0x44, 0xA0, 0xB5, 0x40, 0xA4, 0x5C, 0x18, 0xBA, 0x3C, 0x36, 0x26, 0x4D, 0xD4, 0x8E, 0x96, 0xAF, 0x6A },
|
|
+ { 0xC7, 0x55, 0x8B, 0xAB, 0xDA, 0x04, 0xBC, 0xCB, 0x76, 0x4D, 0x0B, 0xBF, 0x33, 0x58, 0x42, 0x51, 0x41, 0x90, 0x2D, 0x22, 0x39, 0x1D, 0x9F, 0x8C, 0x59, 0x15, 0x9F, 0xEC, 0x9E, 0x49, 0xB1, 0x51 },
|
|
+ { 0x0B, 0x73, 0x2B, 0xB0, 0x35, 0x67, 0x5A, 0x50, 0xFF, 0x58, 0xF2, 0xC2, 0x42, 0xE4, 0x71, 0x0A, 0xEC, 0xE6, 0x46, 0x70, 0x07, 0x9C, 0x13, 0x04, 0x4C, 0x79, 0xC9, 0xB7, 0x49, 0x1F, 0x70, 0x00 },
|
|
+ { 0xD1, 0x20, 0xB5, 0xEF, 0x6D, 0x57, 0xEB, 0xF0, 0x6E, 0xAF, 0x96, 0xBC, 0x93, 0x3C, 0x96, 0x7B, 0x16, 0xCB, 0xE6, 0xE2, 0xBF, 0x00, 0x74, 0x1C, 0x30, 0xAA, 0x1C, 0x54, 0xBA, 0x64, 0x80, 0x1F },
|
|
+ { 0x58, 0xD2, 0x12, 0xAD, 0x6F, 0x58, 0xAE, 0xF0, 0xF8, 0x01, 0x16, 0xB4, 0x41, 0xE5, 0x7F, 0x61, 0x95, 0xBF, 0xEF, 0x26, 0xB6, 0x14, 0x63, 0xED, 0xEC, 0x11, 0x83, 0xCD, 0xB0, 0x4F, 0xE7, 0x6D },
|
|
+ { 0xB8, 0x83, 0x6F, 0x51, 0xD1, 0xE2, 0x9B, 0xDF, 0xDB, 0xA3, 0x25, 0x56, 0x53, 0x60, 0x26, 0x8B, 0x8F, 0xAD, 0x62, 0x74, 0x73, 0xED, 0xEC, 0xEF, 0x7E, 0xAE, 0xFE, 0xE8, 0x37, 0xC7, 0x40, 0x03 },
|
|
+ { 0xC5, 0x47, 0xA3, 0xC1, 0x24, 0xAE, 0x56, 0x85, 0xFF, 0xA7, 0xB8, 0xED, 0xAF, 0x96, 0xEC, 0x86, 0xF8, 0xB2, 0xD0, 0xD5, 0x0C, 0xEE, 0x8B, 0xE3, 0xB1, 0xF0, 0xC7, 0x67, 0x63, 0x06, 0x9D, 0x9C },
|
|
+ { 0x5D, 0x16, 0x8B, 0x76, 0x9A, 0x2F, 0x67, 0x85, 0x3D, 0x62, 0x95, 0xF7, 0x56, 0x8B, 0xE4, 0x0B, 0xB7, 0xA1, 0x6B, 0x8D, 0x65, 0xBA, 0x87, 0x63, 0x5D, 0x19, 0x78, 0xD2, 0xAB, 0x11, 0xBA, 0x2A },
|
|
+ { 0xA2, 0xF6, 0x75, 0xDC, 0x73, 0x02, 0x63, 0x8C, 0xB6, 0x02, 0x01, 0x06, 0x4C, 0xA5, 0x50, 0x77, 0x71, 0x4D, 0x71, 0xFE, 0x09, 0x6A, 0x31, 0x5F, 0x2F, 0xE7, 0x40, 0x12, 0x77, 0xCA, 0xA5, 0xAF },
|
|
+ { 0xC8, 0xAA, 0xB5, 0xCD, 0x01, 0x60, 0xAE, 0x78, 0xCD, 0x2E, 0x8A, 0xC5, 0xFB, 0x0E, 0x09, 0x3C, 0xDB, 0x5C, 0x4B, 0x60, 0x52, 0xA0, 0xA9, 0x7B, 0xB0, 0x42, 0x16, 0x82, 0x6F, 0xA7, 0xA4, 0x37 },
|
|
+ { 0xFF, 0x68, 0xCA, 0x40, 0x35, 0xBF, 0xEB, 0x43, 0xFB, 0xF1, 0x45, 0xFD, 0xDD, 0x5E, 0x43, 0xF1, 0xCE, 0xA5, 0x4F, 0x11, 0xF7, 0xBE, 0xE1, 0x30, 0x58, 0xF0, 0x27, 0x32, 0x9A, 0x4A, 0x5F, 0xA4 },
|
|
+ { 0x1D, 0x4E, 0x54, 0x87, 0xAE, 0x3C, 0x74, 0x0F, 0x2B, 0xA6, 0xE5, 0x41, 0xAC, 0x91, 0xBC, 0x2B, 0xFC, 0xD2, 0x99, 0x9C, 0x51, 0x8D, 0x80, 0x7B, 0x42, 0x67, 0x48, 0x80, 0x3A, 0x35, 0x0F, 0xD4 },
|
|
+ { 0x6D, 0x24, 0x4E, 0x1A, 0x06, 0xCE, 0x4E, 0xF5, 0x78, 0xDD, 0x0F, 0x63, 0xAF, 0xF0, 0x93, 0x67, 0x06, 0x73, 0x51, 0x19, 0xCA, 0x9C, 0x8D, 0x22, 0xD8, 0x6C, 0x80, 0x14, 0x14, 0xAB, 0x97, 0x41 },
|
|
+ { 0xDE, 0xCF, 0x73, 0x29, 0xDB, 0xCC, 0x82, 0x7B, 0x8F, 0xC5, 0x24, 0xC9, 0x43, 0x1E, 0x89, 0x98, 0x02, 0x9E, 0xCE, 0x12, 0xCE, 0x93, 0xB7, 0xB2, 0xF3, 0xE7, 0x69, 0xA9, 0x41, 0xFB, 0x8C, 0xEA },
|
|
+ { 0x2F, 0xAF, 0xCC, 0x0F, 0x2E, 0x63, 0xCB, 0xD0, 0x77, 0x55, 0xBE, 0x7B, 0x75, 0xEC, 0xEA, 0x0A, 0xDF, 0xF9, 0xAA, 0x5E, 0xDE, 0x2A, 0x52, 0xFD, 0xAB, 0x4D, 0xFD, 0x03, 0x74, 0xCD, 0x48, 0x3F },
|
|
+ { 0xAA, 0x85, 0x01, 0x0D, 0xD4, 0x6A, 0x54, 0x6B, 0x53, 0x5E, 0xF4, 0xCF, 0x5F, 0x07, 0xD6, 0x51, 0x61, 0xE8, 0x98, 0x28, 0xF3, 0xA7, 0x7D, 0xB7, 0xB9, 0xB5, 0x6F, 0x0D, 0xF5, 0x9A, 0xAE, 0x45 },
|
|
+ { 0x07, 0xE8, 0xE1, 0xEE, 0x73, 0x2C, 0xB0, 0xD3, 0x56, 0xC9, 0xC0, 0xD1, 0x06, 0x9C, 0x89, 0xD1, 0x7A, 0xDF, 0x6A, 0x9A, 0x33, 0x4F, 0x74, 0x5E, 0xC7, 0x86, 0x73, 0x32, 0x54, 0x8C, 0xA8, 0xE9 },
|
|
+ { 0x0E, 0x01, 0xE8, 0x1C, 0xAD, 0xA8, 0x16, 0x2B, 0xFD, 0x5F, 0x8A, 0x8C, 0x81, 0x8A, 0x6C, 0x69, 0xFE, 0xDF, 0x02, 0xCE, 0xB5, 0x20, 0x85, 0x23, 0xCB, 0xE5, 0x31, 0x3B, 0x89, 0xCA, 0x10, 0x53 },
|
|
+ { 0x6B, 0xB6, 0xC6, 0x47, 0x26, 0x55, 0x08, 0x43, 0x99, 0x85, 0x2E, 0x00, 0x24, 0x9F, 0x8C, 0xB2, 0x47, 0x89, 0x6D, 0x39, 0x2B, 0x02, 0xD7, 0x3B, 0x7F, 0x0D, 0xD8, 0x18, 0xE1, 0xE2, 0x9B, 0x07 },
|
|
+ { 0x42, 0xD4, 0x63, 0x6E, 0x20, 0x60, 0xF0, 0x8F, 0x41, 0xC8, 0x82, 0xE7, 0x6B, 0x39, 0x6B, 0x11, 0x2E, 0xF6, 0x27, 0xCC, 0x24, 0xC4, 0x3D, 0xD5, 0xF8, 0x3A, 0x1D, 0x1A, 0x7E, 0xAD, 0x71, 0x1A },
|
|
+ { 0x48, 0x58, 0xC9, 0xA1, 0x88, 0xB0, 0x23, 0x4F, 0xB9, 0xA8, 0xD4, 0x7D, 0x0B, 0x41, 0x33, 0x65, 0x0A, 0x03, 0x0B, 0xD0, 0x61, 0x1B, 0x87, 0xC3, 0x89, 0x2E, 0x94, 0x95, 0x1F, 0x8D, 0xF8, 0x52 },
|
|
+ { 0x3F, 0xAB, 0x3E, 0x36, 0x98, 0x8D, 0x44, 0x5A, 0x51, 0xC8, 0x78, 0x3E, 0x53, 0x1B, 0xE3, 0xA0, 0x2B, 0xE4, 0x0C, 0xD0, 0x47, 0x96, 0xCF, 0xB6, 0x1D, 0x40, 0x34, 0x74, 0x42, 0xD3, 0xF7, 0x94 },
|
|
+ { 0xEB, 0xAB, 0xC4, 0x96, 0x36, 0xBD, 0x43, 0x3D, 0x2E, 0xC8, 0xF0, 0xE5, 0x18, 0x73, 0x2E, 0xF8, 0xFA, 0x21, 0xD4, 0xD0, 0x71, 0xCC, 0x3B, 0xC4, 0x6C, 0xD7, 0x9F, 0xA3, 0x8A, 0x28, 0xB8, 0x10 },
|
|
+ { 0xA1, 0xD0, 0x34, 0x35, 0x23, 0xB8, 0x93, 0xFC, 0xA8, 0x4F, 0x47, 0xFE, 0xB4, 0xA6, 0x4D, 0x35, 0x0A, 0x17, 0xD8, 0xEE, 0xF5, 0x49, 0x7E, 0xCE, 0x69, 0x7D, 0x02, 0xD7, 0x91, 0x78, 0xB5, 0x91 },
|
|
+ { 0x26, 0x2E, 0xBF, 0xD9, 0x13, 0x0B, 0x7D, 0x28, 0x76, 0x0D, 0x08, 0xEF, 0x8B, 0xFD, 0x3B, 0x86, 0xCD, 0xD3, 0xB2, 0x11, 0x3D, 0x2C, 0xAE, 0xF7, 0xEA, 0x95, 0x1A, 0x30, 0x3D, 0xFA, 0x38, 0x46 },
|
|
+ { 0xF7, 0x61, 0x58, 0xED, 0xD5, 0x0A, 0x15, 0x4F, 0xA7, 0x82, 0x03, 0xED, 0x23, 0x62, 0x93, 0x2F, 0xCB, 0x82, 0x53, 0xAA, 0xE3, 0x78, 0x90, 0x3E, 0xDE, 0xD1, 0xE0, 0x3F, 0x70, 0x21, 0xA2, 0x57 },
|
|
+ { 0x26, 0x17, 0x8E, 0x95, 0x0A, 0xC7, 0x22, 0xF6, 0x7A, 0xE5, 0x6E, 0x57, 0x1B, 0x28, 0x4C, 0x02, 0x07, 0x68, 0x4A, 0x63, 0x34, 0xA1, 0x77, 0x48, 0xA9, 0x4D, 0x26, 0x0B, 0xC5, 0xF5, 0x52, 0x74 },
|
|
+ { 0xC3, 0x78, 0xD1, 0xE4, 0x93, 0xB4, 0x0E, 0xF1, 0x1F, 0xE6, 0xA1, 0x5D, 0x9C, 0x27, 0x37, 0xA3, 0x78, 0x09, 0x63, 0x4C, 0x5A, 0xBA, 0xD5, 0xB3, 0x3D, 0x7E, 0x39, 0x3B, 0x4A, 0xE0, 0x5D, 0x03 },
|
|
+ { 0x98, 0x4B, 0xD8, 0x37, 0x91, 0x01, 0xBE, 0x8F, 0xD8, 0x06, 0x12, 0xD8, 0xEA, 0x29, 0x59, 0xA7, 0x86, 0x5E, 0xC9, 0x71, 0x85, 0x23, 0x55, 0x01, 0x07, 0xAE, 0x39, 0x38, 0xDF, 0x32, 0x01, 0x1B },
|
|
+ { 0xC6, 0xF2, 0x5A, 0x81, 0x2A, 0x14, 0x48, 0x58, 0xAC, 0x5C, 0xED, 0x37, 0xA9, 0x3A, 0x9F, 0x47, 0x59, 0xBA, 0x0B, 0x1C, 0x0F, 0xDC, 0x43, 0x1D, 0xCE, 0x35, 0xF9, 0xEC, 0x1F, 0x1F, 0x4A, 0x99 },
|
|
+ { 0x92, 0x4C, 0x75, 0xC9, 0x44, 0x24, 0xFF, 0x75, 0xE7, 0x4B, 0x8B, 0x4E, 0x94, 0x35, 0x89, 0x58, 0xB0, 0x27, 0xB1, 0x71, 0xDF, 0x5E, 0x57, 0x89, 0x9A, 0xD0, 0xD4, 0xDA, 0xC3, 0x73, 0x53, 0xB6 },
|
|
+ { 0x0A, 0xF3, 0x58, 0x92, 0xA6, 0x3F, 0x45, 0x93, 0x1F, 0x68, 0x46, 0xED, 0x19, 0x03, 0x61, 0xCD, 0x07, 0x30, 0x89, 0xE0, 0x77, 0x16, 0x57, 0x14, 0xB5, 0x0B, 0x81, 0xA2, 0xE3, 0xDD, 0x9B, 0xA1 },
|
|
+ { 0xCC, 0x80, 0xCE, 0xFB, 0x26, 0xC3, 0xB2, 0xB0, 0xDA, 0xEF, 0x23, 0x3E, 0x60, 0x6D, 0x5F, 0xFC, 0x80, 0xFA, 0x17, 0x42, 0x7D, 0x18, 0xE3, 0x04, 0x89, 0x67, 0x3E, 0x06, 0xEF, 0x4B, 0x87, 0xF7 },
|
|
+ { 0xC2, 0xF8, 0xC8, 0x11, 0x74, 0x47, 0xF3, 0x97, 0x8B, 0x08, 0x18, 0xDC, 0xF6, 0xF7, 0x01, 0x16, 0xAC, 0x56, 0xFD, 0x18, 0x4D, 0xD1, 0x27, 0x84, 0x94, 0xE1, 0x03, 0xFC, 0x6D, 0x74, 0xA8, 0x87 },
|
|
+ { 0xBD, 0xEC, 0xF6, 0xBF, 0xC1, 0xBA, 0x0D, 0xF6, 0xE8, 0x62, 0xC8, 0x31, 0x99, 0x22, 0x07, 0x79, 0x6A, 0xCC, 0x79, 0x79, 0x68, 0x35, 0x88, 0x28, 0xC0, 0x6E, 0x7A, 0x51, 0xE0, 0x90, 0x09, 0x8F },
|
|
+ { 0x24, 0xD1, 0xA2, 0x6E, 0x3D, 0xAB, 0x02, 0xFE, 0x45, 0x72, 0xD2, 0xAA, 0x7D, 0xBD, 0x3E, 0xC3, 0x0F, 0x06, 0x93, 0xDB, 0x26, 0xF2, 0x73, 0xD0, 0xAB, 0x2C, 0xB0, 0xC1, 0x3B, 0x5E, 0x64, 0x51 },
|
|
+ { 0xEC, 0x56, 0xF5, 0x8B, 0x09, 0x29, 0x9A, 0x30, 0x0B, 0x14, 0x05, 0x65, 0xD7, 0xD3, 0xE6, 0x87, 0x82, 0xB6, 0xE2, 0xFB, 0xEB, 0x4B, 0x7E, 0xA9, 0x7A, 0xC0, 0x57, 0x98, 0x90, 0x61, 0xDD, 0x3F },
|
|
+ { 0x11, 0xA4, 0x37, 0xC1, 0xAB, 0xA3, 0xC1, 0x19, 0xDD, 0xFA, 0xB3, 0x1B, 0x3E, 0x8C, 0x84, 0x1D, 0xEE, 0xEB, 0x91, 0x3E, 0xF5, 0x7F, 0x7E, 0x48, 0xF2, 0xC9, 0xCF, 0x5A, 0x28, 0xFA, 0x42, 0xBC },
|
|
+ { 0x53, 0xC7, 0xE6, 0x11, 0x4B, 0x85, 0x0A, 0x2C, 0xB4, 0x96, 0xC9, 0xB3, 0xC6, 0x9A, 0x62, 0x3E, 0xAE, 0xA2, 0xCB, 0x1D, 0x33, 0xDD, 0x81, 0x7E, 0x47, 0x65, 0xED, 0xAA, 0x68, 0x23, 0xC2, 0x28 },
|
|
+ { 0x15, 0x4C, 0x3E, 0x96, 0xFE, 0xE5, 0xDB, 0x14, 0xF8, 0x77, 0x3E, 0x18, 0xAF, 0x14, 0x85, 0x79, 0x13, 0x50, 0x9D, 0xA9, 0x99, 0xB4, 0x6C, 0xDD, 0x3D, 0x4C, 0x16, 0x97, 0x60, 0xC8, 0x3A, 0xD2 },
|
|
+ { 0x40, 0xB9, 0x91, 0x6F, 0x09, 0x3E, 0x02, 0x7A, 0x87, 0x86, 0x64, 0x18, 0x18, 0x92, 0x06, 0x20, 0x47, 0x2F, 0xBC, 0xF6, 0x8F, 0x70, 0x1D, 0x1B, 0x68, 0x06, 0x32, 0xE6, 0x99, 0x6B, 0xDE, 0xD3 },
|
|
+ { 0x24, 0xC4, 0xCB, 0xBA, 0x07, 0x11, 0x98, 0x31, 0xA7, 0x26, 0xB0, 0x53, 0x05, 0xD9, 0x6D, 0xA0, 0x2F, 0xF8, 0xB1, 0x48, 0xF0, 0xDA, 0x44, 0x0F, 0xE2, 0x33, 0xBC, 0xAA, 0x32, 0xC7, 0x2F, 0x6F },
|
|
+ { 0x5D, 0x20, 0x15, 0x10, 0x25, 0x00, 0x20, 0xB7, 0x83, 0x68, 0x96, 0x88, 0xAB, 0xBF, 0x8E, 0xCF, 0x25, 0x94, 0xA9, 0x6A, 0x08, 0xF2, 0xBF, 0xEC, 0x6C, 0xE0, 0x57, 0x44, 0x65, 0xDD, 0xED, 0x71 },
|
|
+ { 0x04, 0x3B, 0x97, 0xE3, 0x36, 0xEE, 0x6F, 0xDB, 0xBE, 0x2B, 0x50, 0xF2, 0x2A, 0xF8, 0x32, 0x75, 0xA4, 0x08, 0x48, 0x05, 0xD2, 0xD5, 0x64, 0x59, 0x62, 0x45, 0x4B, 0x6C, 0x9B, 0x80, 0x53, 0xA0 },
|
|
+ { 0x56, 0x48, 0x35, 0xCB, 0xAE, 0xA7, 0x74, 0x94, 0x85, 0x68, 0xBE, 0x36, 0xCF, 0x52, 0xFC, 0xDD, 0x83, 0x93, 0x4E, 0xB0, 0xA2, 0x75, 0x12, 0xDB, 0xE3, 0xE2, 0xDB, 0x47, 0xB9, 0xE6, 0x63, 0x5A },
|
|
+ { 0xF2, 0x1C, 0x33, 0xF4, 0x7B, 0xDE, 0x40, 0xA2, 0xA1, 0x01, 0xC9, 0xCD, 0xE8, 0x02, 0x7A, 0xAF, 0x61, 0xA3, 0x13, 0x7D, 0xE2, 0x42, 0x2B, 0x30, 0x03, 0x5A, 0x04, 0xC2, 0x70, 0x89, 0x41, 0x83 },
|
|
+ { 0x9D, 0xB0, 0xEF, 0x74, 0xE6, 0x6C, 0xBB, 0x84, 0x2E, 0xB0, 0xE0, 0x73, 0x43, 0xA0, 0x3C, 0x5C, 0x56, 0x7E, 0x37, 0x2B, 0x3F, 0x23, 0xB9, 0x43, 0xC7, 0x88, 0xA4, 0xF2, 0x50, 0xF6, 0x78, 0x91 },
|
|
+ { 0xAB, 0x8D, 0x08, 0x65, 0x5F, 0xF1, 0xD3, 0xFE, 0x87, 0x58, 0xD5, 0x62, 0x23, 0x5F, 0xD2, 0x3E, 0x7C, 0xF9, 0xDC, 0xAA, 0xD6, 0x58, 0x87, 0x2A, 0x49, 0xE5, 0xD3, 0x18, 0x3B, 0x6C, 0xCE, 0xBD },
|
|
+ { 0x6F, 0x27, 0xF7, 0x7E, 0x7B, 0xCF, 0x46, 0xA1, 0xE9, 0x63, 0xAD, 0xE0, 0x30, 0x97, 0x33, 0x54, 0x30, 0x31, 0xDC, 0xCD, 0xD4, 0x7C, 0xAA, 0xC1, 0x74, 0xD7, 0xD2, 0x7C, 0xE8, 0x07, 0x7E, 0x8B },
|
|
+ { 0xE3, 0xCD, 0x54, 0xDA, 0x7E, 0x44, 0x4C, 0xAA, 0x62, 0x07, 0x56, 0x95, 0x25, 0xA6, 0x70, 0xEB, 0xAE, 0x12, 0x78, 0xDE, 0x4E, 0x3F, 0xE2, 0x68, 0x4B, 0x3E, 0x33, 0xF5, 0xEF, 0x90, 0xCC, 0x1B },
|
|
+ { 0xB2, 0xC3, 0xE3, 0x3A, 0x51, 0xD2, 0x2C, 0x4C, 0x08, 0xFC, 0x09, 0x89, 0xC8, 0x73, 0xC9, 0xCC, 0x41, 0x50, 0x57, 0x9B, 0x1E, 0x61, 0x63, 0xFA, 0x69, 0x4A, 0xD5, 0x1D, 0x53, 0xD7, 0x12, 0xDC },
|
|
+ { 0xBE, 0x7F, 0xDA, 0x98, 0x3E, 0x13, 0x18, 0x9B, 0x4C, 0x77, 0xE0, 0xA8, 0x09, 0x20, 0xB6, 0xE0, 0xE0, 0xEA, 0x80, 0xC3, 0xB8, 0x4D, 0xBE, 0x7E, 0x71, 0x17, 0xD2, 0x53, 0xF4, 0x81, 0x12, 0xF4 },
|
|
+ { 0xB6, 0x00, 0x8C, 0x28, 0xFA, 0xE0, 0x8A, 0xA4, 0x27, 0xE5, 0xBD, 0x3A, 0xAD, 0x36, 0xF1, 0x00, 0x21, 0xF1, 0x6C, 0x77, 0xCF, 0xEA, 0xBE, 0xD0, 0x7F, 0x97, 0xCC, 0x7D, 0xC1, 0xF1, 0x28, 0x4A },
|
|
+ { 0x6E, 0x4E, 0x67, 0x60, 0xC5, 0x38, 0xF2, 0xE9, 0x7B, 0x3A, 0xDB, 0xFB, 0xBC, 0xDE, 0x57, 0xF8, 0x96, 0x6B, 0x7E, 0xA8, 0xFC, 0xB5, 0xBF, 0x7E, 0xFE, 0xC9, 0x13, 0xFD, 0x2A, 0x2B, 0x0C, 0x55 },
|
|
+ { 0x4A, 0xE5, 0x1F, 0xD1, 0x83, 0x4A, 0xA5, 0xBD, 0x9A, 0x6F, 0x7E, 0xC3, 0x9F, 0xC6, 0x63, 0x33, 0x8D, 0xC5, 0xD2, 0xE2, 0x07, 0x61, 0x56, 0x6D, 0x90, 0xCC, 0x68, 0xB1, 0xCB, 0x87, 0x5E, 0xD8 },
|
|
+ { 0xB6, 0x73, 0xAA, 0xD7, 0x5A, 0xB1, 0xFD, 0xB5, 0x40, 0x1A, 0xBF, 0xA1, 0xBF, 0x89, 0xF3, 0xAD, 0xD2, 0xEB, 0xC4, 0x68, 0xDF, 0x36, 0x24, 0xA4, 0x78, 0xF4, 0xFE, 0x85, 0x9D, 0x8D, 0x55, 0xE2 },
|
|
+ { 0x13, 0xC9, 0x47, 0x1A, 0x98, 0x55, 0x91, 0x35, 0x39, 0x83, 0x66, 0x60, 0x39, 0x8D, 0xA0, 0xF3, 0xF9, 0x9A, 0xDA, 0x08, 0x47, 0x9C, 0x69, 0xD1, 0xB7, 0xFC, 0xAA, 0x34, 0x61, 0xDD, 0x7E, 0x59 },
|
|
+ { 0x2C, 0x11, 0xF4, 0xA7, 0xF9, 0x9A, 0x1D, 0x23, 0xA5, 0x8B, 0xB6, 0x36, 0x35, 0x0F, 0xE8, 0x49, 0xF2, 0x9C, 0xBA, 0xC1, 0xB2, 0xA1, 0x11, 0x2D, 0x9F, 0x1E, 0xD5, 0xBC, 0x5B, 0x31, 0x3C, 0xCD },
|
|
+ { 0xC7, 0xD3, 0xC0, 0x70, 0x6B, 0x11, 0xAE, 0x74, 0x1C, 0x05, 0xA1, 0xEF, 0x15, 0x0D, 0xD6, 0x5B, 0x54, 0x94, 0xD6, 0xD5, 0x4C, 0x9A, 0x86, 0xE2, 0x61, 0x78, 0x54, 0xE6, 0xAE, 0xEE, 0xBB, 0xD9 },
|
|
+ { 0x19, 0x4E, 0x10, 0xC9, 0x38, 0x93, 0xAF, 0xA0, 0x64, 0xC3, 0xAC, 0x04, 0xC0, 0xDD, 0x80, 0x8D, 0x79, 0x1C, 0x3D, 0x4B, 0x75, 0x56, 0xE8, 0x9D, 0x8D, 0x9C, 0xB2, 0x25, 0xC4, 0xB3, 0x33, 0x39 },
|
|
+ { 0x6F, 0xC4, 0x98, 0x8B, 0x8F, 0x78, 0x54, 0x6B, 0x16, 0x88, 0x99, 0x18, 0x45, 0x90, 0x8F, 0x13, 0x4B, 0x6A, 0x48, 0x2E, 0x69, 0x94, 0xB3, 0xD4, 0x83, 0x17, 0xBF, 0x08, 0xDB, 0x29, 0x21, 0x85 },
|
|
+ { 0x56, 0x65, 0xBE, 0xB8, 0xB0, 0x95, 0x55, 0x25, 0x81, 0x3B, 0x59, 0x81, 0xCD, 0x14, 0x2E, 0xD4, 0xD0, 0x3F, 0xBA, 0x38, 0xA6, 0xF3, 0xE5, 0xAD, 0x26, 0x8E, 0x0C, 0xC2, 0x70, 0xD1, 0xCD, 0x11 },
|
|
+ { 0xB8, 0x83, 0xD6, 0x8F, 0x5F, 0xE5, 0x19, 0x36, 0x43, 0x1B, 0xA4, 0x25, 0x67, 0x38, 0x05, 0x3B, 0x1D, 0x04, 0x26, 0xD4, 0xCB, 0x64, 0xB1, 0x6E, 0x83, 0xBA, 0xDC, 0x5E, 0x9F, 0xBE, 0x3B, 0x81 },
|
|
+ { 0x53, 0xE7, 0xB2, 0x7E, 0xA5, 0x9C, 0x2F, 0x6D, 0xBB, 0x50, 0x76, 0x9E, 0x43, 0x55, 0x4D, 0xF3, 0x5A, 0xF8, 0x9F, 0x48, 0x22, 0xD0, 0x46, 0x6B, 0x00, 0x7D, 0xD6, 0xF6, 0xDE, 0xAF, 0xFF, 0x02 },
|
|
+ { 0x1F, 0x1A, 0x02, 0x29, 0xD4, 0x64, 0x0F, 0x01, 0x90, 0x15, 0x88, 0xD9, 0xDE, 0xC2, 0x2D, 0x13, 0xFC, 0x3E, 0xB3, 0x4A, 0x61, 0xB3, 0x29, 0x38, 0xEF, 0xBF, 0x53, 0x34, 0xB2, 0x80, 0x0A, 0xFA },
|
|
+ { 0xC2, 0xB4, 0x05, 0xAF, 0xA0, 0xFA, 0x66, 0x68, 0x85, 0x2A, 0xEE, 0x4D, 0x88, 0x04, 0x08, 0x53, 0xFA, 0xB8, 0x00, 0xE7, 0x2B, 0x57, 0x58, 0x14, 0x18, 0xE5, 0x50, 0x6F, 0x21, 0x4C, 0x7D, 0x1F },
|
|
+ { 0xC0, 0x8A, 0xA1, 0xC2, 0x86, 0xD7, 0x09, 0xFD, 0xC7, 0x47, 0x37, 0x44, 0x97, 0x71, 0x88, 0xC8, 0x95, 0xBA, 0x01, 0x10, 0x14, 0x24, 0x7E, 0x4E, 0xFA, 0x8D, 0x07, 0xE7, 0x8F, 0xEC, 0x69, 0x5C },
|
|
+ { 0xF0, 0x3F, 0x57, 0x89, 0xD3, 0x33, 0x6B, 0x80, 0xD0, 0x02, 0xD5, 0x9F, 0xDF, 0x91, 0x8B, 0xDB, 0x77, 0x5B, 0x00, 0x95, 0x6E, 0xD5, 0x52, 0x8E, 0x86, 0xAA, 0x99, 0x4A, 0xCB, 0x38, 0xFE, 0x2D }
|
|
+};
|
|
+
|
|
+static const u8 blake2s_keyed_testvecs[][BLAKE2S_OUTBYTES] = {
|
|
+ { 0x48, 0xA8, 0x99, 0x7D, 0xA4, 0x07, 0x87, 0x6B, 0x3D, 0x79, 0xC0, 0xD9, 0x23, 0x25, 0xAD, 0x3B, 0x89, 0xCB, 0xB7, 0x54, 0xD8, 0x6A, 0xB7, 0x1A, 0xEE, 0x04, 0x7A, 0xD3, 0x45, 0xFD, 0x2C, 0x49 },
|
|
+ { 0x40, 0xD1, 0x5F, 0xEE, 0x7C, 0x32, 0x88, 0x30, 0x16, 0x6A, 0xC3, 0xF9, 0x18, 0x65, 0x0F, 0x80, 0x7E, 0x7E, 0x01, 0xE1, 0x77, 0x25, 0x8C, 0xDC, 0x0A, 0x39, 0xB1, 0x1F, 0x59, 0x80, 0x66, 0xF1 },
|
|
+ { 0x6B, 0xB7, 0x13, 0x00, 0x64, 0x4C, 0xD3, 0x99, 0x1B, 0x26, 0xCC, 0xD4, 0xD2, 0x74, 0xAC, 0xD1, 0xAD, 0xEA, 0xB8, 0xB1, 0xD7, 0x91, 0x45, 0x46, 0xC1, 0x19, 0x8B, 0xBE, 0x9F, 0xC9, 0xD8, 0x03 },
|
|
+ { 0x1D, 0x22, 0x0D, 0xBE, 0x2E, 0xE1, 0x34, 0x66, 0x1F, 0xDF, 0x6D, 0x9E, 0x74, 0xB4, 0x17, 0x04, 0x71, 0x05, 0x56, 0xF2, 0xF6, 0xE5, 0xA0, 0x91, 0xB2, 0x27, 0x69, 0x74, 0x45, 0xDB, 0xEA, 0x6B },
|
|
+ { 0xF6, 0xC3, 0xFB, 0xAD, 0xB4, 0xCC, 0x68, 0x7A, 0x00, 0x64, 0xA5, 0xBE, 0x6E, 0x79, 0x1B, 0xEC, 0x63, 0xB8, 0x68, 0xAD, 0x62, 0xFB, 0xA6, 0x1B, 0x37, 0x57, 0xEF, 0x9C, 0xA5, 0x2E, 0x05, 0xB2 },
|
|
+ { 0x49, 0xC1, 0xF2, 0x11, 0x88, 0xDF, 0xD7, 0x69, 0xAE, 0xA0, 0xE9, 0x11, 0xDD, 0x6B, 0x41, 0xF1, 0x4D, 0xAB, 0x10, 0x9D, 0x2B, 0x85, 0x97, 0x7A, 0xA3, 0x08, 0x8B, 0x5C, 0x70, 0x7E, 0x85, 0x98 },
|
|
+ { 0xFD, 0xD8, 0x99, 0x3D, 0xCD, 0x43, 0xF6, 0x96, 0xD4, 0x4F, 0x3C, 0xEA, 0x0F, 0xF3, 0x53, 0x45, 0x23, 0x4E, 0xC8, 0xEE, 0x08, 0x3E, 0xB3, 0xCA, 0xDA, 0x01, 0x7C, 0x7F, 0x78, 0xC1, 0x71, 0x43 },
|
|
+ { 0xE6, 0xC8, 0x12, 0x56, 0x37, 0x43, 0x8D, 0x09, 0x05, 0xB7, 0x49, 0xF4, 0x65, 0x60, 0xAC, 0x89, 0xFD, 0x47, 0x1C, 0xF8, 0x69, 0x2E, 0x28, 0xFA, 0xB9, 0x82, 0xF7, 0x3F, 0x01, 0x9B, 0x83, 0xA9 },
|
|
+ { 0x19, 0xFC, 0x8C, 0xA6, 0x97, 0x9D, 0x60, 0xE6, 0xED, 0xD3, 0xB4, 0x54, 0x1E, 0x2F, 0x96, 0x7C, 0xED, 0x74, 0x0D, 0xF6, 0xEC, 0x1E, 0xAE, 0xBB, 0xFE, 0x81, 0x38, 0x32, 0xE9, 0x6B, 0x29, 0x74 },
|
|
+ { 0xA6, 0xAD, 0x77, 0x7C, 0xE8, 0x81, 0xB5, 0x2B, 0xB5, 0xA4, 0x42, 0x1A, 0xB6, 0xCD, 0xD2, 0xDF, 0xBA, 0x13, 0xE9, 0x63, 0x65, 0x2D, 0x4D, 0x6D, 0x12, 0x2A, 0xEE, 0x46, 0x54, 0x8C, 0x14, 0xA7 },
|
|
+ { 0xF5, 0xC4, 0xB2, 0xBA, 0x1A, 0x00, 0x78, 0x1B, 0x13, 0xAB, 0xA0, 0x42, 0x52, 0x42, 0xC6, 0x9C, 0xB1, 0x55, 0x2F, 0x3F, 0x71, 0xA9, 0xA3, 0xBB, 0x22, 0xB4, 0xA6, 0xB4, 0x27, 0x7B, 0x46, 0xDD },
|
|
+ { 0xE3, 0x3C, 0x4C, 0x9B, 0xD0, 0xCC, 0x7E, 0x45, 0xC8, 0x0E, 0x65, 0xC7, 0x7F, 0xA5, 0x99, 0x7F, 0xEC, 0x70, 0x02, 0x73, 0x85, 0x41, 0x50, 0x9E, 0x68, 0xA9, 0x42, 0x38, 0x91, 0xE8, 0x22, 0xA3 },
|
|
+ { 0xFB, 0xA1, 0x61, 0x69, 0xB2, 0xC3, 0xEE, 0x10, 0x5B, 0xE6, 0xE1, 0xE6, 0x50, 0xE5, 0xCB, 0xF4, 0x07, 0x46, 0xB6, 0x75, 0x3D, 0x03, 0x6A, 0xB5, 0x51, 0x79, 0x01, 0x4A, 0xD7, 0xEF, 0x66, 0x51 },
|
|
+ { 0xF5, 0xC4, 0xBE, 0xC6, 0xD6, 0x2F, 0xC6, 0x08, 0xBF, 0x41, 0xCC, 0x11, 0x5F, 0x16, 0xD6, 0x1C, 0x7E, 0xFD, 0x3F, 0xF6, 0xC6, 0x56, 0x92, 0xBB, 0xE0, 0xAF, 0xFF, 0xB1, 0xFE, 0xDE, 0x74, 0x75 },
|
|
+ { 0xA4, 0x86, 0x2E, 0x76, 0xDB, 0x84, 0x7F, 0x05, 0xBA, 0x17, 0xED, 0xE5, 0xDA, 0x4E, 0x7F, 0x91, 0xB5, 0x92, 0x5C, 0xF1, 0xAD, 0x4B, 0xA1, 0x27, 0x32, 0xC3, 0x99, 0x57, 0x42, 0xA5, 0xCD, 0x6E },
|
|
+ { 0x65, 0xF4, 0xB8, 0x60, 0xCD, 0x15, 0xB3, 0x8E, 0xF8, 0x14, 0xA1, 0xA8, 0x04, 0x31, 0x4A, 0x55, 0xBE, 0x95, 0x3C, 0xAA, 0x65, 0xFD, 0x75, 0x8A, 0xD9, 0x89, 0xFF, 0x34, 0xA4, 0x1C, 0x1E, 0xEA },
|
|
+ { 0x19, 0xBA, 0x23, 0x4F, 0x0A, 0x4F, 0x38, 0x63, 0x7D, 0x18, 0x39, 0xF9, 0xD9, 0xF7, 0x6A, 0xD9, 0x1C, 0x85, 0x22, 0x30, 0x71, 0x43, 0xC9, 0x7D, 0x5F, 0x93, 0xF6, 0x92, 0x74, 0xCE, 0xC9, 0xA7 },
|
|
+ { 0x1A, 0x67, 0x18, 0x6C, 0xA4, 0xA5, 0xCB, 0x8E, 0x65, 0xFC, 0xA0, 0xE2, 0xEC, 0xBC, 0x5D, 0xDC, 0x14, 0xAE, 0x38, 0x1B, 0xB8, 0xBF, 0xFE, 0xB9, 0xE0, 0xA1, 0x03, 0x44, 0x9E, 0x3E, 0xF0, 0x3C },
|
|
+ { 0xAF, 0xBE, 0xA3, 0x17, 0xB5, 0xA2, 0xE8, 0x9C, 0x0B, 0xD9, 0x0C, 0xCF, 0x5D, 0x7F, 0xD0, 0xED, 0x57, 0xFE, 0x58, 0x5E, 0x4B, 0xE3, 0x27, 0x1B, 0x0A, 0x6B, 0xF0, 0xF5, 0x78, 0x6B, 0x0F, 0x26 },
|
|
+ { 0xF1, 0xB0, 0x15, 0x58, 0xCE, 0x54, 0x12, 0x62, 0xF5, 0xEC, 0x34, 0x29, 0x9D, 0x6F, 0xB4, 0x09, 0x00, 0x09, 0xE3, 0x43, 0x4B, 0xE2, 0xF4, 0x91, 0x05, 0xCF, 0x46, 0xAF, 0x4D, 0x2D, 0x41, 0x24 },
|
|
+ { 0x13, 0xA0, 0xA0, 0xC8, 0x63, 0x35, 0x63, 0x5E, 0xAA, 0x74, 0xCA, 0x2D, 0x5D, 0x48, 0x8C, 0x79, 0x7B, 0xBB, 0x4F, 0x47, 0xDC, 0x07, 0x10, 0x50, 0x15, 0xED, 0x6A, 0x1F, 0x33, 0x09, 0xEF, 0xCE },
|
|
+ { 0x15, 0x80, 0xAF, 0xEE, 0xBE, 0xBB, 0x34, 0x6F, 0x94, 0xD5, 0x9F, 0xE6, 0x2D, 0xA0, 0xB7, 0x92, 0x37, 0xEA, 0xD7, 0xB1, 0x49, 0x1F, 0x56, 0x67, 0xA9, 0x0E, 0x45, 0xED, 0xF6, 0xCA, 0x8B, 0x03 },
|
|
+ { 0x20, 0xBE, 0x1A, 0x87, 0x5B, 0x38, 0xC5, 0x73, 0xDD, 0x7F, 0xAA, 0xA0, 0xDE, 0x48, 0x9D, 0x65, 0x5C, 0x11, 0xEF, 0xB6, 0xA5, 0x52, 0x69, 0x8E, 0x07, 0xA2, 0xD3, 0x31, 0xB5, 0xF6, 0x55, 0xC3 },
|
|
+ { 0xBE, 0x1F, 0xE3, 0xC4, 0xC0, 0x40, 0x18, 0xC5, 0x4C, 0x4A, 0x0F, 0x6B, 0x9A, 0x2E, 0xD3, 0xC5, 0x3A, 0xBE, 0x3A, 0x9F, 0x76, 0xB4, 0xD2, 0x6D, 0xE5, 0x6F, 0xC9, 0xAE, 0x95, 0x05, 0x9A, 0x99 },
|
|
+ { 0xE3, 0xE3, 0xAC, 0xE5, 0x37, 0xEB, 0x3E, 0xDD, 0x84, 0x63, 0xD9, 0xAD, 0x35, 0x82, 0xE1, 0x3C, 0xF8, 0x65, 0x33, 0xFF, 0xDE, 0x43, 0xD6, 0x68, 0xDD, 0x2E, 0x93, 0xBB, 0xDB, 0xD7, 0x19, 0x5A },
|
|
+ { 0x11, 0x0C, 0x50, 0xC0, 0xBF, 0x2C, 0x6E, 0x7A, 0xEB, 0x7E, 0x43, 0x5D, 0x92, 0xD1, 0x32, 0xAB, 0x66, 0x55, 0x16, 0x8E, 0x78, 0xA2, 0xDE, 0xCD, 0xEC, 0x33, 0x30, 0x77, 0x76, 0x84, 0xD9, 0xC1 },
|
|
+ { 0xE9, 0xBA, 0x8F, 0x50, 0x5C, 0x9C, 0x80, 0xC0, 0x86, 0x66, 0xA7, 0x01, 0xF3, 0x36, 0x7E, 0x6C, 0xC6, 0x65, 0xF3, 0x4B, 0x22, 0xE7, 0x3C, 0x3C, 0x04, 0x17, 0xEB, 0x1C, 0x22, 0x06, 0x08, 0x2F },
|
|
+ { 0x26, 0xCD, 0x66, 0xFC, 0xA0, 0x23, 0x79, 0xC7, 0x6D, 0xF1, 0x23, 0x17, 0x05, 0x2B, 0xCA, 0xFD, 0x6C, 0xD8, 0xC3, 0xA7, 0xB8, 0x90, 0xD8, 0x05, 0xF3, 0x6C, 0x49, 0x98, 0x97, 0x82, 0x43, 0x3A },
|
|
+ { 0x21, 0x3F, 0x35, 0x96, 0xD6, 0xE3, 0xA5, 0xD0, 0xE9, 0x93, 0x2C, 0xD2, 0x15, 0x91, 0x46, 0x01, 0x5E, 0x2A, 0xBC, 0x94, 0x9F, 0x47, 0x29, 0xEE, 0x26, 0x32, 0xFE, 0x1E, 0xDB, 0x78, 0xD3, 0x37 },
|
|
+ { 0x10, 0x15, 0xD7, 0x01, 0x08, 0xE0, 0x3B, 0xE1, 0xC7, 0x02, 0xFE, 0x97, 0x25, 0x36, 0x07, 0xD1, 0x4A, 0xEE, 0x59, 0x1F, 0x24, 0x13, 0xEA, 0x67, 0x87, 0x42, 0x7B, 0x64, 0x59, 0xFF, 0x21, 0x9A },
|
|
+ { 0x3C, 0xA9, 0x89, 0xDE, 0x10, 0xCF, 0xE6, 0x09, 0x90, 0x94, 0x72, 0xC8, 0xD3, 0x56, 0x10, 0x80, 0x5B, 0x2F, 0x97, 0x77, 0x34, 0xCF, 0x65, 0x2C, 0xC6, 0x4B, 0x3B, 0xFC, 0x88, 0x2D, 0x5D, 0x89 },
|
|
+ { 0xB6, 0x15, 0x6F, 0x72, 0xD3, 0x80, 0xEE, 0x9E, 0xA6, 0xAC, 0xD1, 0x90, 0x46, 0x4F, 0x23, 0x07, 0xA5, 0xC1, 0x79, 0xEF, 0x01, 0xFD, 0x71, 0xF9, 0x9F, 0x2D, 0x0F, 0x7A, 0x57, 0x36, 0x0A, 0xEA },
|
|
+ { 0xC0, 0x3B, 0xC6, 0x42, 0xB2, 0x09, 0x59, 0xCB, 0xE1, 0x33, 0xA0, 0x30, 0x3E, 0x0C, 0x1A, 0xBF, 0xF3, 0xE3, 0x1E, 0xC8, 0xE1, 0xA3, 0x28, 0xEC, 0x85, 0x65, 0xC3, 0x6D, 0xEC, 0xFF, 0x52, 0x65 },
|
|
+ { 0x2C, 0x3E, 0x08, 0x17, 0x6F, 0x76, 0x0C, 0x62, 0x64, 0xC3, 0xA2, 0xCD, 0x66, 0xFE, 0xC6, 0xC3, 0xD7, 0x8D, 0xE4, 0x3F, 0xC1, 0x92, 0x45, 0x7B, 0x2A, 0x4A, 0x66, 0x0A, 0x1E, 0x0E, 0xB2, 0x2B },
|
|
+ { 0xF7, 0x38, 0xC0, 0x2F, 0x3C, 0x1B, 0x19, 0x0C, 0x51, 0x2B, 0x1A, 0x32, 0xDE, 0xAB, 0xF3, 0x53, 0x72, 0x8E, 0x0E, 0x9A, 0xB0, 0x34, 0x49, 0x0E, 0x3C, 0x34, 0x09, 0x94, 0x6A, 0x97, 0xAE, 0xEC },
|
|
+ { 0x8B, 0x18, 0x80, 0xDF, 0x30, 0x1C, 0xC9, 0x63, 0x41, 0x88, 0x11, 0x08, 0x89, 0x64, 0x83, 0x92, 0x87, 0xFF, 0x7F, 0xE3, 0x1C, 0x49, 0xEA, 0x6E, 0xBD, 0x9E, 0x48, 0xBD, 0xEE, 0xE4, 0x97, 0xC5 },
|
|
+ { 0x1E, 0x75, 0xCB, 0x21, 0xC6, 0x09, 0x89, 0x02, 0x03, 0x75, 0xF1, 0xA7, 0xA2, 0x42, 0x83, 0x9F, 0x0B, 0x0B, 0x68, 0x97, 0x3A, 0x4C, 0x2A, 0x05, 0xCF, 0x75, 0x55, 0xED, 0x5A, 0xAE, 0xC4, 0xC1 },
|
|
+ { 0x62, 0xBF, 0x8A, 0x9C, 0x32, 0xA5, 0xBC, 0xCF, 0x29, 0x0B, 0x6C, 0x47, 0x4D, 0x75, 0xB2, 0xA2, 0xA4, 0x09, 0x3F, 0x1A, 0x9E, 0x27, 0x13, 0x94, 0x33, 0xA8, 0xF2, 0xB3, 0xBC, 0xE7, 0xB8, 0xD7 },
|
|
+ { 0x16, 0x6C, 0x83, 0x50, 0xD3, 0x17, 0x3B, 0x5E, 0x70, 0x2B, 0x78, 0x3D, 0xFD, 0x33, 0xC6, 0x6E, 0xE0, 0x43, 0x27, 0x42, 0xE9, 0xB9, 0x2B, 0x99, 0x7F, 0xD2, 0x3C, 0x60, 0xDC, 0x67, 0x56, 0xCA },
|
|
+ { 0x04, 0x4A, 0x14, 0xD8, 0x22, 0xA9, 0x0C, 0xAC, 0xF2, 0xF5, 0xA1, 0x01, 0x42, 0x8A, 0xDC, 0x8F, 0x41, 0x09, 0x38, 0x6C, 0xCB, 0x15, 0x8B, 0xF9, 0x05, 0xC8, 0x61, 0x8B, 0x8E, 0xE2, 0x4E, 0xC3 },
|
|
+ { 0x38, 0x7D, 0x39, 0x7E, 0xA4, 0x3A, 0x99, 0x4B, 0xE8, 0x4D, 0x2D, 0x54, 0x4A, 0xFB, 0xE4, 0x81, 0xA2, 0x00, 0x0F, 0x55, 0x25, 0x26, 0x96, 0xBB, 0xA2, 0xC5, 0x0C, 0x8E, 0xBD, 0x10, 0x13, 0x47 },
|
|
+ { 0x56, 0xF8, 0xCC, 0xF1, 0xF8, 0x64, 0x09, 0xB4, 0x6C, 0xE3, 0x61, 0x66, 0xAE, 0x91, 0x65, 0x13, 0x84, 0x41, 0x57, 0x75, 0x89, 0xDB, 0x08, 0xCB, 0xC5, 0xF6, 0x6C, 0xA2, 0x97, 0x43, 0xB9, 0xFD },
|
|
+ { 0x97, 0x06, 0xC0, 0x92, 0xB0, 0x4D, 0x91, 0xF5, 0x3D, 0xFF, 0x91, 0xFA, 0x37, 0xB7, 0x49, 0x3D, 0x28, 0xB5, 0x76, 0xB5, 0xD7, 0x10, 0x46, 0x9D, 0xF7, 0x94, 0x01, 0x66, 0x22, 0x36, 0xFC, 0x03 },
|
|
+ { 0x87, 0x79, 0x68, 0x68, 0x6C, 0x06, 0x8C, 0xE2, 0xF7, 0xE2, 0xAD, 0xCF, 0xF6, 0x8B, 0xF8, 0x74, 0x8E, 0xDF, 0x3C, 0xF8, 0x62, 0xCF, 0xB4, 0xD3, 0x94, 0x7A, 0x31, 0x06, 0x95, 0x80, 0x54, 0xE3 },
|
|
+ { 0x88, 0x17, 0xE5, 0x71, 0x98, 0x79, 0xAC, 0xF7, 0x02, 0x47, 0x87, 0xEC, 0xCD, 0xB2, 0x71, 0x03, 0x55, 0x66, 0xCF, 0xA3, 0x33, 0xE0, 0x49, 0x40, 0x7C, 0x01, 0x78, 0xCC, 0xC5, 0x7A, 0x5B, 0x9F },
|
|
+ { 0x89, 0x38, 0x24, 0x9E, 0x4B, 0x50, 0xCA, 0xDA, 0xCC, 0xDF, 0x5B, 0x18, 0x62, 0x13, 0x26, 0xCB, 0xB1, 0x52, 0x53, 0xE3, 0x3A, 0x20, 0xF5, 0x63, 0x6E, 0x99, 0x5D, 0x72, 0x47, 0x8D, 0xE4, 0x72 },
|
|
+ { 0xF1, 0x64, 0xAB, 0xBA, 0x49, 0x63, 0xA4, 0x4D, 0x10, 0x72, 0x57, 0xE3, 0x23, 0x2D, 0x90, 0xAC, 0xA5, 0xE6, 0x6A, 0x14, 0x08, 0x24, 0x8C, 0x51, 0x74, 0x1E, 0x99, 0x1D, 0xB5, 0x22, 0x77, 0x56 },
|
|
+ { 0xD0, 0x55, 0x63, 0xE2, 0xB1, 0xCB, 0xA0, 0xC4, 0xA2, 0xA1, 0xE8, 0xBD, 0xE3, 0xA1, 0xA0, 0xD9, 0xF5, 0xB4, 0x0C, 0x85, 0xA0, 0x70, 0xD6, 0xF5, 0xFB, 0x21, 0x06, 0x6E, 0xAD, 0x5D, 0x06, 0x01 },
|
|
+ { 0x03, 0xFB, 0xB1, 0x63, 0x84, 0xF0, 0xA3, 0x86, 0x6F, 0x4C, 0x31, 0x17, 0x87, 0x76, 0x66, 0xEF, 0xBF, 0x12, 0x45, 0x97, 0x56, 0x4B, 0x29, 0x3D, 0x4A, 0xAB, 0x0D, 0x26, 0x9F, 0xAB, 0xDD, 0xFA },
|
|
+ { 0x5F, 0xA8, 0x48, 0x6A, 0xC0, 0xE5, 0x29, 0x64, 0xD1, 0x88, 0x1B, 0xBE, 0x33, 0x8E, 0xB5, 0x4B, 0xE2, 0xF7, 0x19, 0x54, 0x92, 0x24, 0x89, 0x20, 0x57, 0xB4, 0xDA, 0x04, 0xBA, 0x8B, 0x34, 0x75 },
|
|
+ { 0xCD, 0xFA, 0xBC, 0xEE, 0x46, 0x91, 0x11, 0x11, 0x23, 0x6A, 0x31, 0x70, 0x8B, 0x25, 0x39, 0xD7, 0x1F, 0xC2, 0x11, 0xD9, 0xB0, 0x9C, 0x0D, 0x85, 0x30, 0xA1, 0x1E, 0x1D, 0xBF, 0x6E, 0xED, 0x01 },
|
|
+ { 0x4F, 0x82, 0xDE, 0x03, 0xB9, 0x50, 0x47, 0x93, 0xB8, 0x2A, 0x07, 0xA0, 0xBD, 0xCD, 0xFF, 0x31, 0x4D, 0x75, 0x9E, 0x7B, 0x62, 0xD2, 0x6B, 0x78, 0x49, 0x46, 0xB0, 0xD3, 0x6F, 0x91, 0x6F, 0x52 },
|
|
+ { 0x25, 0x9E, 0xC7, 0xF1, 0x73, 0xBC, 0xC7, 0x6A, 0x09, 0x94, 0xC9, 0x67, 0xB4, 0xF5, 0xF0, 0x24, 0xC5, 0x60, 0x57, 0xFB, 0x79, 0xC9, 0x65, 0xC4, 0xFA, 0xE4, 0x18, 0x75, 0xF0, 0x6A, 0x0E, 0x4C },
|
|
+ { 0x19, 0x3C, 0xC8, 0xE7, 0xC3, 0xE0, 0x8B, 0xB3, 0x0F, 0x54, 0x37, 0xAA, 0x27, 0xAD, 0xE1, 0xF1, 0x42, 0x36, 0x9B, 0x24, 0x6A, 0x67, 0x5B, 0x23, 0x83, 0xE6, 0xDA, 0x9B, 0x49, 0xA9, 0x80, 0x9E },
|
|
+ { 0x5C, 0x10, 0x89, 0x6F, 0x0E, 0x28, 0x56, 0xB2, 0xA2, 0xEE, 0xE0, 0xFE, 0x4A, 0x2C, 0x16, 0x33, 0x56, 0x5D, 0x18, 0xF0, 0xE9, 0x3E, 0x1F, 0xAB, 0x26, 0xC3, 0x73, 0xE8, 0xF8, 0x29, 0x65, 0x4D },
|
|
+ { 0xF1, 0x60, 0x12, 0xD9, 0x3F, 0x28, 0x85, 0x1A, 0x1E, 0xB9, 0x89, 0xF5, 0xD0, 0xB4, 0x3F, 0x3F, 0x39, 0xCA, 0x73, 0xC9, 0xA6, 0x2D, 0x51, 0x81, 0xBF, 0xF2, 0x37, 0x53, 0x6B, 0xD3, 0x48, 0xC3 },
|
|
+ { 0x29, 0x66, 0xB3, 0xCF, 0xAE, 0x1E, 0x44, 0xEA, 0x99, 0x6D, 0xC5, 0xD6, 0x86, 0xCF, 0x25, 0xFA, 0x05, 0x3F, 0xB6, 0xF6, 0x72, 0x01, 0xB9, 0xE4, 0x6E, 0xAD, 0xE8, 0x5D, 0x0A, 0xD6, 0xB8, 0x06 },
|
|
+ { 0xDD, 0xB8, 0x78, 0x24, 0x85, 0xE9, 0x00, 0xBC, 0x60, 0xBC, 0xF4, 0xC3, 0x3A, 0x6F, 0xD5, 0x85, 0x68, 0x0C, 0xC6, 0x83, 0xD5, 0x16, 0xEF, 0xA0, 0x3E, 0xB9, 0x98, 0x5F, 0xAD, 0x87, 0x15, 0xFB },
|
|
+ { 0x4C, 0x4D, 0x6E, 0x71, 0xAE, 0xA0, 0x57, 0x86, 0x41, 0x31, 0x48, 0xFC, 0x7A, 0x78, 0x6B, 0x0E, 0xCA, 0xF5, 0x82, 0xCF, 0xF1, 0x20, 0x9F, 0x5A, 0x80, 0x9F, 0xBA, 0x85, 0x04, 0xCE, 0x66, 0x2C },
|
|
+ { 0xFB, 0x4C, 0x5E, 0x86, 0xD7, 0xB2, 0x22, 0x9B, 0x99, 0xB8, 0xBA, 0x6D, 0x94, 0xC2, 0x47, 0xEF, 0x96, 0x4A, 0xA3, 0xA2, 0xBA, 0xE8, 0xED, 0xC7, 0x75, 0x69, 0xF2, 0x8D, 0xBB, 0xFF, 0x2D, 0x4E },
|
|
+ { 0xE9, 0x4F, 0x52, 0x6D, 0xE9, 0x01, 0x96, 0x33, 0xEC, 0xD5, 0x4A, 0xC6, 0x12, 0x0F, 0x23, 0x95, 0x8D, 0x77, 0x18, 0xF1, 0xE7, 0x71, 0x7B, 0xF3, 0x29, 0x21, 0x1A, 0x4F, 0xAE, 0xED, 0x4E, 0x6D },
|
|
+ { 0xCB, 0xD6, 0x66, 0x0A, 0x10, 0xDB, 0x3F, 0x23, 0xF7, 0xA0, 0x3D, 0x4B, 0x9D, 0x40, 0x44, 0xC7, 0x93, 0x2B, 0x28, 0x01, 0xAC, 0x89, 0xD6, 0x0B, 0xC9, 0xEB, 0x92, 0xD6, 0x5A, 0x46, 0xC2, 0xA0 },
|
|
+ { 0x88, 0x18, 0xBB, 0xD3, 0xDB, 0x4D, 0xC1, 0x23, 0xB2, 0x5C, 0xBB, 0xA5, 0xF5, 0x4C, 0x2B, 0xC4, 0xB3, 0xFC, 0xF9, 0xBF, 0x7D, 0x7A, 0x77, 0x09, 0xF4, 0xAE, 0x58, 0x8B, 0x26, 0x7C, 0x4E, 0xCE },
|
|
+ { 0xC6, 0x53, 0x82, 0x51, 0x3F, 0x07, 0x46, 0x0D, 0xA3, 0x98, 0x33, 0xCB, 0x66, 0x6C, 0x5E, 0xD8, 0x2E, 0x61, 0xB9, 0xE9, 0x98, 0xF4, 0xB0, 0xC4, 0x28, 0x7C, 0xEE, 0x56, 0xC3, 0xCC, 0x9B, 0xCD },
|
|
+ { 0x89, 0x75, 0xB0, 0x57, 0x7F, 0xD3, 0x55, 0x66, 0xD7, 0x50, 0xB3, 0x62, 0xB0, 0x89, 0x7A, 0x26, 0xC3, 0x99, 0x13, 0x6D, 0xF0, 0x7B, 0xAB, 0xAB, 0xBD, 0xE6, 0x20, 0x3F, 0xF2, 0x95, 0x4E, 0xD4 },
|
|
+ { 0x21, 0xFE, 0x0C, 0xEB, 0x00, 0x52, 0xBE, 0x7F, 0xB0, 0xF0, 0x04, 0x18, 0x7C, 0xAC, 0xD7, 0xDE, 0x67, 0xFA, 0x6E, 0xB0, 0x93, 0x8D, 0x92, 0x76, 0x77, 0xF2, 0x39, 0x8C, 0x13, 0x23, 0x17, 0xA8 },
|
|
+ { 0x2E, 0xF7, 0x3F, 0x3C, 0x26, 0xF1, 0x2D, 0x93, 0x88, 0x9F, 0x3C, 0x78, 0xB6, 0xA6, 0x6C, 0x1D, 0x52, 0xB6, 0x49, 0xDC, 0x9E, 0x85, 0x6E, 0x2C, 0x17, 0x2E, 0xA7, 0xC5, 0x8A, 0xC2, 0xB5, 0xE3 },
|
|
+ { 0x38, 0x8A, 0x3C, 0xD5, 0x6D, 0x73, 0x86, 0x7A, 0xBB, 0x5F, 0x84, 0x01, 0x49, 0x2B, 0x6E, 0x26, 0x81, 0xEB, 0x69, 0x85, 0x1E, 0x76, 0x7F, 0xD8, 0x42, 0x10, 0xA5, 0x60, 0x76, 0xFB, 0x3D, 0xD3 },
|
|
+ { 0xAF, 0x53, 0x3E, 0x02, 0x2F, 0xC9, 0x43, 0x9E, 0x4E, 0x3C, 0xB8, 0x38, 0xEC, 0xD1, 0x86, 0x92, 0x23, 0x2A, 0xDF, 0x6F, 0xE9, 0x83, 0x95, 0x26, 0xD3, 0xC3, 0xDD, 0x1B, 0x71, 0x91, 0x0B, 0x1A },
|
|
+ { 0x75, 0x1C, 0x09, 0xD4, 0x1A, 0x93, 0x43, 0x88, 0x2A, 0x81, 0xCD, 0x13, 0xEE, 0x40, 0x81, 0x8D, 0x12, 0xEB, 0x44, 0xC6, 0xC7, 0xF4, 0x0D, 0xF1, 0x6E, 0x4A, 0xEA, 0x8F, 0xAB, 0x91, 0x97, 0x2A },
|
|
+ { 0x5B, 0x73, 0xDD, 0xB6, 0x8D, 0x9D, 0x2B, 0x0A, 0xA2, 0x65, 0xA0, 0x79, 0x88, 0xD6, 0xB8, 0x8A, 0xE9, 0xAA, 0xC5, 0x82, 0xAF, 0x83, 0x03, 0x2F, 0x8A, 0x9B, 0x21, 0xA2, 0xE1, 0xB7, 0xBF, 0x18 },
|
|
+ { 0x3D, 0xA2, 0x91, 0x26, 0xC7, 0xC5, 0xD7, 0xF4, 0x3E, 0x64, 0x24, 0x2A, 0x79, 0xFE, 0xAA, 0x4E, 0xF3, 0x45, 0x9C, 0xDE, 0xCC, 0xC8, 0x98, 0xED, 0x59, 0xA9, 0x7F, 0x6E, 0xC9, 0x3B, 0x9D, 0xAB },
|
|
+ { 0x56, 0x6D, 0xC9, 0x20, 0x29, 0x3D, 0xA5, 0xCB, 0x4F, 0xE0, 0xAA, 0x8A, 0xBD, 0xA8, 0xBB, 0xF5, 0x6F, 0x55, 0x23, 0x13, 0xBF, 0xF1, 0x90, 0x46, 0x64, 0x1E, 0x36, 0x15, 0xC1, 0xE3, 0xED, 0x3F },
|
|
+ { 0x41, 0x15, 0xBE, 0xA0, 0x2F, 0x73, 0xF9, 0x7F, 0x62, 0x9E, 0x5C, 0x55, 0x90, 0x72, 0x0C, 0x01, 0xE7, 0xE4, 0x49, 0xAE, 0x2A, 0x66, 0x97, 0xD4, 0xD2, 0x78, 0x33, 0x21, 0x30, 0x36, 0x92, 0xF9 },
|
|
+ { 0x4C, 0xE0, 0x8F, 0x47, 0x62, 0x46, 0x8A, 0x76, 0x70, 0x01, 0x21, 0x64, 0x87, 0x8D, 0x68, 0x34, 0x0C, 0x52, 0xA3, 0x5E, 0x66, 0xC1, 0x88, 0x4D, 0x5C, 0x86, 0x48, 0x89, 0xAB, 0xC9, 0x66, 0x77 },
|
|
+ { 0x81, 0xEA, 0x0B, 0x78, 0x04, 0x12, 0x4E, 0x0C, 0x22, 0xEA, 0x5F, 0xC7, 0x11, 0x04, 0xA2, 0xAF, 0xCB, 0x52, 0xA1, 0xFA, 0x81, 0x6F, 0x3E, 0xCB, 0x7D, 0xCB, 0x5D, 0x9D, 0xEA, 0x17, 0x86, 0xD0 },
|
|
+ { 0xFE, 0x36, 0x27, 0x33, 0xB0, 0x5F, 0x6B, 0xED, 0xAF, 0x93, 0x79, 0xD7, 0xF7, 0x93, 0x6E, 0xDE, 0x20, 0x9B, 0x1F, 0x83, 0x23, 0xC3, 0x92, 0x25, 0x49, 0xD9, 0xE7, 0x36, 0x81, 0xB5, 0xDB, 0x7B },
|
|
+ { 0xEF, 0xF3, 0x7D, 0x30, 0xDF, 0xD2, 0x03, 0x59, 0xBE, 0x4E, 0x73, 0xFD, 0xF4, 0x0D, 0x27, 0x73, 0x4B, 0x3D, 0xF9, 0x0A, 0x97, 0xA5, 0x5E, 0xD7, 0x45, 0x29, 0x72, 0x94, 0xCA, 0x85, 0xD0, 0x9F },
|
|
+ { 0x17, 0x2F, 0xFC, 0x67, 0x15, 0x3D, 0x12, 0xE0, 0xCA, 0x76, 0xA8, 0xB6, 0xCD, 0x5D, 0x47, 0x31, 0x88, 0x5B, 0x39, 0xCE, 0x0C, 0xAC, 0x93, 0xA8, 0x97, 0x2A, 0x18, 0x00, 0x6C, 0x8B, 0x8B, 0xAF },
|
|
+ { 0xC4, 0x79, 0x57, 0xF1, 0xCC, 0x88, 0xE8, 0x3E, 0xF9, 0x44, 0x58, 0x39, 0x70, 0x9A, 0x48, 0x0A, 0x03, 0x6B, 0xED, 0x5F, 0x88, 0xAC, 0x0F, 0xCC, 0x8E, 0x1E, 0x70, 0x3F, 0xFA, 0xAC, 0x13, 0x2C },
|
|
+ { 0x30, 0xF3, 0x54, 0x83, 0x70, 0xCF, 0xDC, 0xED, 0xA5, 0xC3, 0x7B, 0x56, 0x9B, 0x61, 0x75, 0xE7, 0x99, 0xEE, 0xF1, 0xA6, 0x2A, 0xAA, 0x94, 0x32, 0x45, 0xAE, 0x76, 0x69, 0xC2, 0x27, 0xA7, 0xB5 },
|
|
+ { 0xC9, 0x5D, 0xCB, 0x3C, 0xF1, 0xF2, 0x7D, 0x0E, 0xEF, 0x2F, 0x25, 0xD2, 0x41, 0x38, 0x70, 0x90, 0x4A, 0x87, 0x7C, 0x4A, 0x56, 0xC2, 0xDE, 0x1E, 0x83, 0xE2, 0xBC, 0x2A, 0xE2, 0xE4, 0x68, 0x21 },
|
|
+ { 0xD5, 0xD0, 0xB5, 0xD7, 0x05, 0x43, 0x4C, 0xD4, 0x6B, 0x18, 0x57, 0x49, 0xF6, 0x6B, 0xFB, 0x58, 0x36, 0xDC, 0xDF, 0x6E, 0xE5, 0x49, 0xA2, 0xB7, 0xA4, 0xAE, 0xE7, 0xF5, 0x80, 0x07, 0xCA, 0xAF },
|
|
+ { 0xBB, 0xC1, 0x24, 0xA7, 0x12, 0xF1, 0x5D, 0x07, 0xC3, 0x00, 0xE0, 0x5B, 0x66, 0x83, 0x89, 0xA4, 0x39, 0xC9, 0x17, 0x77, 0xF7, 0x21, 0xF8, 0x32, 0x0C, 0x1C, 0x90, 0x78, 0x06, 0x6D, 0x2C, 0x7E },
|
|
+ { 0xA4, 0x51, 0xB4, 0x8C, 0x35, 0xA6, 0xC7, 0x85, 0x4C, 0xFA, 0xAE, 0x60, 0x26, 0x2E, 0x76, 0x99, 0x08, 0x16, 0x38, 0x2A, 0xC0, 0x66, 0x7E, 0x5A, 0x5C, 0x9E, 0x1B, 0x46, 0xC4, 0x34, 0x2D, 0xDF },
|
|
+ { 0xB0, 0xD1, 0x50, 0xFB, 0x55, 0xE7, 0x78, 0xD0, 0x11, 0x47, 0xF0, 0xB5, 0xD8, 0x9D, 0x99, 0xEC, 0xB2, 0x0F, 0xF0, 0x7E, 0x5E, 0x67, 0x60, 0xD6, 0xB6, 0x45, 0xEB, 0x5B, 0x65, 0x4C, 0x62, 0x2B },
|
|
+ { 0x34, 0xF7, 0x37, 0xC0, 0xAB, 0x21, 0x99, 0x51, 0xEE, 0xE8, 0x9A, 0x9F, 0x8D, 0xAC, 0x29, 0x9C, 0x9D, 0x4C, 0x38, 0xF3, 0x3F, 0xA4, 0x94, 0xC5, 0xC6, 0xEE, 0xFC, 0x92, 0xB6, 0xDB, 0x08, 0xBC },
|
|
+ { 0x1A, 0x62, 0xCC, 0x3A, 0x00, 0x80, 0x0D, 0xCB, 0xD9, 0x98, 0x91, 0x08, 0x0C, 0x1E, 0x09, 0x84, 0x58, 0x19, 0x3A, 0x8C, 0xC9, 0xF9, 0x70, 0xEA, 0x99, 0xFB, 0xEF, 0xF0, 0x03, 0x18, 0xC2, 0x89 },
|
|
+ { 0xCF, 0xCE, 0x55, 0xEB, 0xAF, 0xC8, 0x40, 0xD7, 0xAE, 0x48, 0x28, 0x1C, 0x7F, 0xD5, 0x7E, 0xC8, 0xB4, 0x82, 0xD4, 0xB7, 0x04, 0x43, 0x74, 0x95, 0x49, 0x5A, 0xC4, 0x14, 0xCF, 0x4A, 0x37, 0x4B },
|
|
+ { 0x67, 0x46, 0xFA, 0xCF, 0x71, 0x14, 0x6D, 0x99, 0x9D, 0xAB, 0xD0, 0x5D, 0x09, 0x3A, 0xE5, 0x86, 0x64, 0x8D, 0x1E, 0xE2, 0x8E, 0x72, 0x61, 0x7B, 0x99, 0xD0, 0xF0, 0x08, 0x6E, 0x1E, 0x45, 0xBF },
|
|
+ { 0x57, 0x1C, 0xED, 0x28, 0x3B, 0x3F, 0x23, 0xB4, 0xE7, 0x50, 0xBF, 0x12, 0xA2, 0xCA, 0xF1, 0x78, 0x18, 0x47, 0xBD, 0x89, 0x0E, 0x43, 0x60, 0x3C, 0xDC, 0x59, 0x76, 0x10, 0x2B, 0x7B, 0xB1, 0x1B },
|
|
+ { 0xCF, 0xCB, 0x76, 0x5B, 0x04, 0x8E, 0x35, 0x02, 0x2C, 0x5D, 0x08, 0x9D, 0x26, 0xE8, 0x5A, 0x36, 0xB0, 0x05, 0xA2, 0xB8, 0x04, 0x93, 0xD0, 0x3A, 0x14, 0x4E, 0x09, 0xF4, 0x09, 0xB6, 0xAF, 0xD1 },
|
|
+ { 0x40, 0x50, 0xC7, 0xA2, 0x77, 0x05, 0xBB, 0x27, 0xF4, 0x20, 0x89, 0xB2, 0x99, 0xF3, 0xCB, 0xE5, 0x05, 0x4E, 0xAD, 0x68, 0x72, 0x7E, 0x8E, 0xF9, 0x31, 0x8C, 0xE6, 0xF2, 0x5C, 0xD6, 0xF3, 0x1D },
|
|
+ { 0x18, 0x40, 0x70, 0xBD, 0x5D, 0x26, 0x5F, 0xBD, 0xC1, 0x42, 0xCD, 0x1C, 0x5C, 0xD0, 0xD7, 0xE4, 0x14, 0xE7, 0x03, 0x69, 0xA2, 0x66, 0xD6, 0x27, 0xC8, 0xFB, 0xA8, 0x4F, 0xA5, 0xE8, 0x4C, 0x34 },
|
|
+ { 0x9E, 0xDD, 0xA9, 0xA4, 0x44, 0x39, 0x02, 0xA9, 0x58, 0x8C, 0x0D, 0x0C, 0xCC, 0x62, 0xB9, 0x30, 0x21, 0x84, 0x79, 0xA6, 0x84, 0x1E, 0x6F, 0xE7, 0xD4, 0x30, 0x03, 0xF0, 0x4B, 0x1F, 0xD6, 0x43 },
|
|
+ { 0xE4, 0x12, 0xFE, 0xEF, 0x79, 0x08, 0x32, 0x4A, 0x6D, 0xA1, 0x84, 0x16, 0x29, 0xF3, 0x5D, 0x3D, 0x35, 0x86, 0x42, 0x01, 0x93, 0x10, 0xEC, 0x57, 0xC6, 0x14, 0x83, 0x6B, 0x63, 0xD3, 0x07, 0x63 },
|
|
+ { 0x1A, 0x2B, 0x8E, 0xDF, 0xF3, 0xF9, 0xAC, 0xC1, 0x55, 0x4F, 0xCB, 0xAE, 0x3C, 0xF1, 0xD6, 0x29, 0x8C, 0x64, 0x62, 0xE2, 0x2E, 0x5E, 0xB0, 0x25, 0x96, 0x84, 0xF8, 0x35, 0x01, 0x2B, 0xD1, 0x3F },
|
|
+ { 0x28, 0x8C, 0x4A, 0xD9, 0xB9, 0x40, 0x97, 0x62, 0xEA, 0x07, 0xC2, 0x4A, 0x41, 0xF0, 0x4F, 0x69, 0xA7, 0xD7, 0x4B, 0xEE, 0x2D, 0x95, 0x43, 0x53, 0x74, 0xBD, 0xE9, 0x46, 0xD7, 0x24, 0x1C, 0x7B },
|
|
+ { 0x80, 0x56, 0x91, 0xBB, 0x28, 0x67, 0x48, 0xCF, 0xB5, 0x91, 0xD3, 0xAE, 0xBE, 0x7E, 0x6F, 0x4E, 0x4D, 0xC6, 0xE2, 0x80, 0x8C, 0x65, 0x14, 0x3C, 0xC0, 0x04, 0xE4, 0xEB, 0x6F, 0xD0, 0x9D, 0x43 },
|
|
+ { 0xD4, 0xAC, 0x8D, 0x3A, 0x0A, 0xFC, 0x6C, 0xFA, 0x7B, 0x46, 0x0A, 0xE3, 0x00, 0x1B, 0xAE, 0xB3, 0x6D, 0xAD, 0xB3, 0x7D, 0xA0, 0x7D, 0x2E, 0x8A, 0xC9, 0x18, 0x22, 0xDF, 0x34, 0x8A, 0xED, 0x3D },
|
|
+ { 0xC3, 0x76, 0x61, 0x70, 0x14, 0xD2, 0x01, 0x58, 0xBC, 0xED, 0x3D, 0x3B, 0xA5, 0x52, 0xB6, 0xEC, 0xCF, 0x84, 0xE6, 0x2A, 0xA3, 0xEB, 0x65, 0x0E, 0x90, 0x02, 0x9C, 0x84, 0xD1, 0x3E, 0xEA, 0x69 },
|
|
+ { 0xC4, 0x1F, 0x09, 0xF4, 0x3C, 0xEC, 0xAE, 0x72, 0x93, 0xD6, 0x00, 0x7C, 0xA0, 0xA3, 0x57, 0x08, 0x7D, 0x5A, 0xE5, 0x9B, 0xE5, 0x00, 0xC1, 0xCD, 0x5B, 0x28, 0x9E, 0xE8, 0x10, 0xC7, 0xB0, 0x82 },
|
|
+ { 0x03, 0xD1, 0xCE, 0xD1, 0xFB, 0xA5, 0xC3, 0x91, 0x55, 0xC4, 0x4B, 0x77, 0x65, 0xCB, 0x76, 0x0C, 0x78, 0x70, 0x8D, 0xCF, 0xC8, 0x0B, 0x0B, 0xD8, 0xAD, 0xE3, 0xA5, 0x6D, 0xA8, 0x83, 0x0B, 0x29 },
|
|
+ { 0x09, 0xBD, 0xE6, 0xF1, 0x52, 0x21, 0x8D, 0xC9, 0x2C, 0x41, 0xD7, 0xF4, 0x53, 0x87, 0xE6, 0x3E, 0x58, 0x69, 0xD8, 0x07, 0xEC, 0x70, 0xB8, 0x21, 0x40, 0x5D, 0xBD, 0x88, 0x4B, 0x7F, 0xCF, 0x4B },
|
|
+ { 0x71, 0xC9, 0x03, 0x6E, 0x18, 0x17, 0x9B, 0x90, 0xB3, 0x7D, 0x39, 0xE9, 0xF0, 0x5E, 0xB8, 0x9C, 0xC5, 0xFC, 0x34, 0x1F, 0xD7, 0xC4, 0x77, 0xD0, 0xD7, 0x49, 0x32, 0x85, 0xFA, 0xCA, 0x08, 0xA4 },
|
|
+ { 0x59, 0x16, 0x83, 0x3E, 0xBB, 0x05, 0xCD, 0x91, 0x9C, 0xA7, 0xFE, 0x83, 0xB6, 0x92, 0xD3, 0x20, 0x5B, 0xEF, 0x72, 0x39, 0x2B, 0x2C, 0xF6, 0xBB, 0x0A, 0x6D, 0x43, 0xF9, 0x94, 0xF9, 0x5F, 0x11 },
|
|
+ { 0xF6, 0x3A, 0xAB, 0x3E, 0xC6, 0x41, 0xB3, 0xB0, 0x24, 0x96, 0x4C, 0x2B, 0x43, 0x7C, 0x04, 0xF6, 0x04, 0x3C, 0x4C, 0x7E, 0x02, 0x79, 0x23, 0x99, 0x95, 0x40, 0x19, 0x58, 0xF8, 0x6B, 0xBE, 0x54 },
|
|
+ { 0xF1, 0x72, 0xB1, 0x80, 0xBF, 0xB0, 0x97, 0x40, 0x49, 0x31, 0x20, 0xB6, 0x32, 0x6C, 0xBD, 0xC5, 0x61, 0xE4, 0x77, 0xDE, 0xF9, 0xBB, 0xCF, 0xD2, 0x8C, 0xC8, 0xC1, 0xC5, 0xE3, 0x37, 0x9A, 0x31 },
|
|
+ { 0xCB, 0x9B, 0x89, 0xCC, 0x18, 0x38, 0x1D, 0xD9, 0x14, 0x1A, 0xDE, 0x58, 0x86, 0x54, 0xD4, 0xE6, 0xA2, 0x31, 0xD5, 0xBF, 0x49, 0xD4, 0xD5, 0x9A, 0xC2, 0x7D, 0x86, 0x9C, 0xBE, 0x10, 0x0C, 0xF3 },
|
|
+ { 0x7B, 0xD8, 0x81, 0x50, 0x46, 0xFD, 0xD8, 0x10, 0xA9, 0x23, 0xE1, 0x98, 0x4A, 0xAE, 0xBD, 0xCD, 0xF8, 0x4D, 0x87, 0xC8, 0x99, 0x2D, 0x68, 0xB5, 0xEE, 0xB4, 0x60, 0xF9, 0x3E, 0xB3, 0xC8, 0xD7 },
|
|
+ { 0x60, 0x7B, 0xE6, 0x68, 0x62, 0xFD, 0x08, 0xEE, 0x5B, 0x19, 0xFA, 0xCA, 0xC0, 0x9D, 0xFD, 0xBC, 0xD4, 0x0C, 0x31, 0x21, 0x01, 0xD6, 0x6E, 0x6E, 0xBD, 0x2B, 0x84, 0x1F, 0x1B, 0x9A, 0x93, 0x25 },
|
|
+ { 0x9F, 0xE0, 0x3B, 0xBE, 0x69, 0xAB, 0x18, 0x34, 0xF5, 0x21, 0x9B, 0x0D, 0xA8, 0x8A, 0x08, 0xB3, 0x0A, 0x66, 0xC5, 0x91, 0x3F, 0x01, 0x51, 0x96, 0x3C, 0x36, 0x05, 0x60, 0xDB, 0x03, 0x87, 0xB3 },
|
|
+ { 0x90, 0xA8, 0x35, 0x85, 0x71, 0x7B, 0x75, 0xF0, 0xE9, 0xB7, 0x25, 0xE0, 0x55, 0xEE, 0xEE, 0xB9, 0xE7, 0xA0, 0x28, 0xEA, 0x7E, 0x6C, 0xBC, 0x07, 0xB2, 0x09, 0x17, 0xEC, 0x03, 0x63, 0xE3, 0x8C },
|
|
+ { 0x33, 0x6E, 0xA0, 0x53, 0x0F, 0x4A, 0x74, 0x69, 0x12, 0x6E, 0x02, 0x18, 0x58, 0x7E, 0xBB, 0xDE, 0x33, 0x58, 0xA0, 0xB3, 0x1C, 0x29, 0xD2, 0x00, 0xF7, 0xDC, 0x7E, 0xB1, 0x5C, 0x6A, 0xAD, 0xD8 },
|
|
+ { 0xA7, 0x9E, 0x76, 0xDC, 0x0A, 0xBC, 0xA4, 0x39, 0x6F, 0x07, 0x47, 0xCD, 0x7B, 0x74, 0x8D, 0xF9, 0x13, 0x00, 0x76, 0x26, 0xB1, 0xD6, 0x59, 0xDA, 0x0C, 0x1F, 0x78, 0xB9, 0x30, 0x3D, 0x01, 0xA3 },
|
|
+ { 0x44, 0xE7, 0x8A, 0x77, 0x37, 0x56, 0xE0, 0x95, 0x15, 0x19, 0x50, 0x4D, 0x70, 0x38, 0xD2, 0x8D, 0x02, 0x13, 0xA3, 0x7E, 0x0C, 0xE3, 0x75, 0x37, 0x17, 0x57, 0xBC, 0x99, 0x63, 0x11, 0xE3, 0xB8 },
|
|
+ { 0x77, 0xAC, 0x01, 0x2A, 0x3F, 0x75, 0x4D, 0xCF, 0xEA, 0xB5, 0xEB, 0x99, 0x6B, 0xE9, 0xCD, 0x2D, 0x1F, 0x96, 0x11, 0x1B, 0x6E, 0x49, 0xF3, 0x99, 0x4D, 0xF1, 0x81, 0xF2, 0x85, 0x69, 0xD8, 0x25 },
|
|
+ { 0xCE, 0x5A, 0x10, 0xDB, 0x6F, 0xCC, 0xDA, 0xF1, 0x40, 0xAA, 0xA4, 0xDE, 0xD6, 0x25, 0x0A, 0x9C, 0x06, 0xE9, 0x22, 0x2B, 0xC9, 0xF9, 0xF3, 0x65, 0x8A, 0x4A, 0xFF, 0x93, 0x5F, 0x2B, 0x9F, 0x3A },
|
|
+ { 0xEC, 0xC2, 0x03, 0xA7, 0xFE, 0x2B, 0xE4, 0xAB, 0xD5, 0x5B, 0xB5, 0x3E, 0x6E, 0x67, 0x35, 0x72, 0xE0, 0x07, 0x8D, 0xA8, 0xCD, 0x37, 0x5E, 0xF4, 0x30, 0xCC, 0x97, 0xF9, 0xF8, 0x00, 0x83, 0xAF },
|
|
+ { 0x14, 0xA5, 0x18, 0x6D, 0xE9, 0xD7, 0xA1, 0x8B, 0x04, 0x12, 0xB8, 0x56, 0x3E, 0x51, 0xCC, 0x54, 0x33, 0x84, 0x0B, 0x4A, 0x12, 0x9A, 0x8F, 0xF9, 0x63, 0xB3, 0x3A, 0x3C, 0x4A, 0xFE, 0x8E, 0xBB },
|
|
+ { 0x13, 0xF8, 0xEF, 0x95, 0xCB, 0x86, 0xE6, 0xA6, 0x38, 0x93, 0x1C, 0x8E, 0x10, 0x76, 0x73, 0xEB, 0x76, 0xBA, 0x10, 0xD7, 0xC2, 0xCD, 0x70, 0xB9, 0xD9, 0x92, 0x0B, 0xBE, 0xED, 0x92, 0x94, 0x09 },
|
|
+ { 0x0B, 0x33, 0x8F, 0x4E, 0xE1, 0x2F, 0x2D, 0xFC, 0xB7, 0x87, 0x13, 0x37, 0x79, 0x41, 0xE0, 0xB0, 0x63, 0x21, 0x52, 0x58, 0x1D, 0x13, 0x32, 0x51, 0x6E, 0x4A, 0x2C, 0xAB, 0x19, 0x42, 0xCC, 0xA4 },
|
|
+ { 0xEA, 0xAB, 0x0E, 0xC3, 0x7B, 0x3B, 0x8A, 0xB7, 0x96, 0xE9, 0xF5, 0x72, 0x38, 0xDE, 0x14, 0xA2, 0x64, 0xA0, 0x76, 0xF3, 0x88, 0x7D, 0x86, 0xE2, 0x9B, 0xB5, 0x90, 0x6D, 0xB5, 0xA0, 0x0E, 0x02 },
|
|
+ { 0x23, 0xCB, 0x68, 0xB8, 0xC0, 0xE6, 0xDC, 0x26, 0xDC, 0x27, 0x76, 0x6D, 0xDC, 0x0A, 0x13, 0xA9, 0x94, 0x38, 0xFD, 0x55, 0x61, 0x7A, 0xA4, 0x09, 0x5D, 0x8F, 0x96, 0x97, 0x20, 0xC8, 0x72, 0xDF },
|
|
+ { 0x09, 0x1D, 0x8E, 0xE3, 0x0D, 0x6F, 0x29, 0x68, 0xD4, 0x6B, 0x68, 0x7D, 0xD6, 0x52, 0x92, 0x66, 0x57, 0x42, 0xDE, 0x0B, 0xB8, 0x3D, 0xCC, 0x00, 0x04, 0xC7, 0x2C, 0xE1, 0x00, 0x07, 0xA5, 0x49 },
|
|
+ { 0x7F, 0x50, 0x7A, 0xBC, 0x6D, 0x19, 0xBA, 0x00, 0xC0, 0x65, 0xA8, 0x76, 0xEC, 0x56, 0x57, 0x86, 0x88, 0x82, 0xD1, 0x8A, 0x22, 0x1B, 0xC4, 0x6C, 0x7A, 0x69, 0x12, 0x54, 0x1F, 0x5B, 0xC7, 0xBA },
|
|
+ { 0xA0, 0x60, 0x7C, 0x24, 0xE1, 0x4E, 0x8C, 0x22, 0x3D, 0xB0, 0xD7, 0x0B, 0x4D, 0x30, 0xEE, 0x88, 0x01, 0x4D, 0x60, 0x3F, 0x43, 0x7E, 0x9E, 0x02, 0xAA, 0x7D, 0xAF, 0xA3, 0xCD, 0xFB, 0xAD, 0x94 },
|
|
+ { 0xDD, 0xBF, 0xEA, 0x75, 0xCC, 0x46, 0x78, 0x82, 0xEB, 0x34, 0x83, 0xCE, 0x5E, 0x2E, 0x75, 0x6A, 0x4F, 0x47, 0x01, 0xB7, 0x6B, 0x44, 0x55, 0x19, 0xE8, 0x9F, 0x22, 0xD6, 0x0F, 0xA8, 0x6E, 0x06 },
|
|
+ { 0x0C, 0x31, 0x1F, 0x38, 0xC3, 0x5A, 0x4F, 0xB9, 0x0D, 0x65, 0x1C, 0x28, 0x9D, 0x48, 0x68, 0x56, 0xCD, 0x14, 0x13, 0xDF, 0x9B, 0x06, 0x77, 0xF5, 0x3E, 0xCE, 0x2C, 0xD9, 0xE4, 0x77, 0xC6, 0x0A },
|
|
+ { 0x46, 0xA7, 0x3A, 0x8D, 0xD3, 0xE7, 0x0F, 0x59, 0xD3, 0x94, 0x2C, 0x01, 0xDF, 0x59, 0x9D, 0xEF, 0x78, 0x3C, 0x9D, 0xA8, 0x2F, 0xD8, 0x32, 0x22, 0xCD, 0x66, 0x2B, 0x53, 0xDC, 0xE7, 0xDB, 0xDF },
|
|
+ { 0xAD, 0x03, 0x8F, 0xF9, 0xB1, 0x4D, 0xE8, 0x4A, 0x80, 0x1E, 0x4E, 0x62, 0x1C, 0xE5, 0xDF, 0x02, 0x9D, 0xD9, 0x35, 0x20, 0xD0, 0xC2, 0xFA, 0x38, 0xBF, 0xF1, 0x76, 0xA8, 0xB1, 0xD1, 0x69, 0x8C },
|
|
+ { 0xAB, 0x70, 0xC5, 0xDF, 0xBD, 0x1E, 0xA8, 0x17, 0xFE, 0xD0, 0xCD, 0x06, 0x72, 0x93, 0xAB, 0xF3, 0x19, 0xE5, 0xD7, 0x90, 0x1C, 0x21, 0x41, 0xD5, 0xD9, 0x9B, 0x23, 0xF0, 0x3A, 0x38, 0xE7, 0x48 },
|
|
+ { 0x1F, 0xFF, 0xDA, 0x67, 0x93, 0x2B, 0x73, 0xC8, 0xEC, 0xAF, 0x00, 0x9A, 0x34, 0x91, 0xA0, 0x26, 0x95, 0x3B, 0xAB, 0xFE, 0x1F, 0x66, 0x3B, 0x06, 0x97, 0xC3, 0xC4, 0xAE, 0x8B, 0x2E, 0x7D, 0xCB },
|
|
+ { 0xB0, 0xD2, 0xCC, 0x19, 0x47, 0x2D, 0xD5, 0x7F, 0x2B, 0x17, 0xEF, 0xC0, 0x3C, 0x8D, 0x58, 0xC2, 0x28, 0x3D, 0xBB, 0x19, 0xDA, 0x57, 0x2F, 0x77, 0x55, 0x85, 0x5A, 0xA9, 0x79, 0x43, 0x17, 0xA0 },
|
|
+ { 0xA0, 0xD1, 0x9A, 0x6E, 0xE3, 0x39, 0x79, 0xC3, 0x25, 0x51, 0x0E, 0x27, 0x66, 0x22, 0xDF, 0x41, 0xF7, 0x15, 0x83, 0xD0, 0x75, 0x01, 0xB8, 0x70, 0x71, 0x12, 0x9A, 0x0A, 0xD9, 0x47, 0x32, 0xA5 },
|
|
+ { 0x72, 0x46, 0x42, 0xA7, 0x03, 0x2D, 0x10, 0x62, 0xB8, 0x9E, 0x52, 0xBE, 0xA3, 0x4B, 0x75, 0xDF, 0x7D, 0x8F, 0xE7, 0x72, 0xD9, 0xFE, 0x3C, 0x93, 0xDD, 0xF3, 0xC4, 0x54, 0x5A, 0xB5, 0xA9, 0x9B },
|
|
+ { 0xAD, 0xE5, 0xEA, 0xA7, 0xE6, 0x1F, 0x67, 0x2D, 0x58, 0x7E, 0xA0, 0x3D, 0xAE, 0x7D, 0x7B, 0x55, 0x22, 0x9C, 0x01, 0xD0, 0x6B, 0xC0, 0xA5, 0x70, 0x14, 0x36, 0xCB, 0xD1, 0x83, 0x66, 0xA6, 0x26 },
|
|
+ { 0x01, 0x3B, 0x31, 0xEB, 0xD2, 0x28, 0xFC, 0xDD, 0xA5, 0x1F, 0xAB, 0xB0, 0x3B, 0xB0, 0x2D, 0x60, 0xAC, 0x20, 0xCA, 0x21, 0x5A, 0xAF, 0xA8, 0x3B, 0xDD, 0x85, 0x5E, 0x37, 0x55, 0xA3, 0x5F, 0x0B },
|
|
+ { 0x33, 0x2E, 0xD4, 0x0B, 0xB1, 0x0D, 0xDE, 0x3C, 0x95, 0x4A, 0x75, 0xD7, 0xB8, 0x99, 0x9D, 0x4B, 0x26, 0xA1, 0xC0, 0x63, 0xC1, 0xDC, 0x6E, 0x32, 0xC1, 0xD9, 0x1B, 0xAB, 0x7B, 0xBB, 0x7D, 0x16 },
|
|
+ { 0xC7, 0xA1, 0x97, 0xB3, 0xA0, 0x5B, 0x56, 0x6B, 0xCC, 0x9F, 0xAC, 0xD2, 0x0E, 0x44, 0x1D, 0x6F, 0x6C, 0x28, 0x60, 0xAC, 0x96, 0x51, 0xCD, 0x51, 0xD6, 0xB9, 0xD2, 0xCD, 0xEE, 0xEA, 0x03, 0x90 },
|
|
+ { 0xBD, 0x9C, 0xF6, 0x4E, 0xA8, 0x95, 0x3C, 0x03, 0x71, 0x08, 0xE6, 0xF6, 0x54, 0x91, 0x4F, 0x39, 0x58, 0xB6, 0x8E, 0x29, 0xC1, 0x67, 0x00, 0xDC, 0x18, 0x4D, 0x94, 0xA2, 0x17, 0x08, 0xFF, 0x60 },
|
|
+ { 0x88, 0x35, 0xB0, 0xAC, 0x02, 0x11, 0x51, 0xDF, 0x71, 0x64, 0x74, 0xCE, 0x27, 0xCE, 0x4D, 0x3C, 0x15, 0xF0, 0xB2, 0xDA, 0xB4, 0x80, 0x03, 0xCF, 0x3F, 0x3E, 0xFD, 0x09, 0x45, 0x10, 0x6B, 0x9A },
|
|
+ { 0x3B, 0xFE, 0xFA, 0x33, 0x01, 0xAA, 0x55, 0xC0, 0x80, 0x19, 0x0C, 0xFF, 0xDA, 0x8E, 0xAE, 0x51, 0xD9, 0xAF, 0x48, 0x8B, 0x4C, 0x1F, 0x24, 0xC3, 0xD9, 0xA7, 0x52, 0x42, 0xFD, 0x8E, 0xA0, 0x1D },
|
|
+ { 0x08, 0x28, 0x4D, 0x14, 0x99, 0x3C, 0xD4, 0x7D, 0x53, 0xEB, 0xAE, 0xCF, 0x0D, 0xF0, 0x47, 0x8C, 0xC1, 0x82, 0xC8, 0x9C, 0x00, 0xE1, 0x85, 0x9C, 0x84, 0x85, 0x16, 0x86, 0xDD, 0xF2, 0xC1, 0xB7 },
|
|
+ { 0x1E, 0xD7, 0xEF, 0x9F, 0x04, 0xC2, 0xAC, 0x8D, 0xB6, 0xA8, 0x64, 0xDB, 0x13, 0x10, 0x87, 0xF2, 0x70, 0x65, 0x09, 0x8E, 0x69, 0xC3, 0xFE, 0x78, 0x71, 0x8D, 0x9B, 0x94, 0x7F, 0x4A, 0x39, 0xD0 },
|
|
+ { 0xC1, 0x61, 0xF2, 0xDC, 0xD5, 0x7E, 0x9C, 0x14, 0x39, 0xB3, 0x1A, 0x9D, 0xD4, 0x3D, 0x8F, 0x3D, 0x7D, 0xD8, 0xF0, 0xEB, 0x7C, 0xFA, 0xC6, 0xFB, 0x25, 0xA0, 0xF2, 0x8E, 0x30, 0x6F, 0x06, 0x61 },
|
|
+ { 0xC0, 0x19, 0x69, 0xAD, 0x34, 0xC5, 0x2C, 0xAF, 0x3D, 0xC4, 0xD8, 0x0D, 0x19, 0x73, 0x5C, 0x29, 0x73, 0x1A, 0xC6, 0xE7, 0xA9, 0x20, 0x85, 0xAB, 0x92, 0x50, 0xC4, 0x8D, 0xEA, 0x48, 0xA3, 0xFC },
|
|
+ { 0x17, 0x20, 0xB3, 0x65, 0x56, 0x19, 0xD2, 0xA5, 0x2B, 0x35, 0x21, 0xAE, 0x0E, 0x49, 0xE3, 0x45, 0xCB, 0x33, 0x89, 0xEB, 0xD6, 0x20, 0x8A, 0xCA, 0xF9, 0xF1, 0x3F, 0xDA, 0xCC, 0xA8, 0xBE, 0x49 },
|
|
+ { 0x75, 0x62, 0x88, 0x36, 0x1C, 0x83, 0xE2, 0x4C, 0x61, 0x7C, 0xF9, 0x5C, 0x90, 0x5B, 0x22, 0xD0, 0x17, 0xCD, 0xC8, 0x6F, 0x0B, 0xF1, 0xD6, 0x58, 0xF4, 0x75, 0x6C, 0x73, 0x79, 0x87, 0x3B, 0x7F },
|
|
+ { 0xE7, 0xD0, 0xED, 0xA3, 0x45, 0x26, 0x93, 0xB7, 0x52, 0xAB, 0xCD, 0xA1, 0xB5, 0x5E, 0x27, 0x6F, 0x82, 0x69, 0x8F, 0x5F, 0x16, 0x05, 0x40, 0x3E, 0xFF, 0x83, 0x0B, 0xEA, 0x00, 0x71, 0xA3, 0x94 },
|
|
+ { 0x2C, 0x82, 0xEC, 0xAA, 0x6B, 0x84, 0x80, 0x3E, 0x04, 0x4A, 0xF6, 0x31, 0x18, 0xAF, 0xE5, 0x44, 0x68, 0x7C, 0xB6, 0xE6, 0xC7, 0xDF, 0x49, 0xED, 0x76, 0x2D, 0xFD, 0x7C, 0x86, 0x93, 0xA1, 0xBC },
|
|
+ { 0x61, 0x36, 0xCB, 0xF4, 0xB4, 0x41, 0x05, 0x6F, 0xA1, 0xE2, 0x72, 0x24, 0x98, 0x12, 0x5D, 0x6D, 0xED, 0x45, 0xE1, 0x7B, 0x52, 0x14, 0x39, 0x59, 0xC7, 0xF4, 0xD4, 0xE3, 0x95, 0x21, 0x8A, 0xC2 },
|
|
+ { 0x72, 0x1D, 0x32, 0x45, 0xAA, 0xFE, 0xF2, 0x7F, 0x6A, 0x62, 0x4F, 0x47, 0x95, 0x4B, 0x6C, 0x25, 0x50, 0x79, 0x52, 0x6F, 0xFA, 0x25, 0xE9, 0xFF, 0x77, 0xE5, 0xDC, 0xFF, 0x47, 0x3B, 0x15, 0x97 },
|
|
+ { 0x9D, 0xD2, 0xFB, 0xD8, 0xCE, 0xF1, 0x6C, 0x35, 0x3C, 0x0A, 0xC2, 0x11, 0x91, 0xD5, 0x09, 0xEB, 0x28, 0xDD, 0x9E, 0x3E, 0x0D, 0x8C, 0xEA, 0x5D, 0x26, 0xCA, 0x83, 0x93, 0x93, 0x85, 0x1C, 0x3A },
|
|
+ { 0xB2, 0x39, 0x4C, 0xEA, 0xCD, 0xEB, 0xF2, 0x1B, 0xF9, 0xDF, 0x2C, 0xED, 0x98, 0xE5, 0x8F, 0x1C, 0x3A, 0x4B, 0xBB, 0xFF, 0x66, 0x0D, 0xD9, 0x00, 0xF6, 0x22, 0x02, 0xD6, 0x78, 0x5C, 0xC4, 0x6E },
|
|
+ { 0x57, 0x08, 0x9F, 0x22, 0x27, 0x49, 0xAD, 0x78, 0x71, 0x76, 0x5F, 0x06, 0x2B, 0x11, 0x4F, 0x43, 0xBA, 0x20, 0xEC, 0x56, 0x42, 0x2A, 0x8B, 0x1E, 0x3F, 0x87, 0x19, 0x2C, 0x0E, 0xA7, 0x18, 0xC6 },
|
|
+ { 0xE4, 0x9A, 0x94, 0x59, 0x96, 0x1C, 0xD3, 0x3C, 0xDF, 0x4A, 0xAE, 0x1B, 0x10, 0x78, 0xA5, 0xDE, 0xA7, 0xC0, 0x40, 0xE0, 0xFE, 0xA3, 0x40, 0xC9, 0x3A, 0x72, 0x48, 0x72, 0xFC, 0x4A, 0xF8, 0x06 },
|
|
+ { 0xED, 0xE6, 0x7F, 0x72, 0x0E, 0xFF, 0xD2, 0xCA, 0x9C, 0x88, 0x99, 0x41, 0x52, 0xD0, 0x20, 0x1D, 0xEE, 0x6B, 0x0A, 0x2D, 0x2C, 0x07, 0x7A, 0xCA, 0x6D, 0xAE, 0x29, 0xF7, 0x3F, 0x8B, 0x63, 0x09 },
|
|
+ { 0xE0, 0xF4, 0x34, 0xBF, 0x22, 0xE3, 0x08, 0x80, 0x39, 0xC2, 0x1F, 0x71, 0x9F, 0xFC, 0x67, 0xF0, 0xF2, 0xCB, 0x5E, 0x98, 0xA7, 0xA0, 0x19, 0x4C, 0x76, 0xE9, 0x6B, 0xF4, 0xE8, 0xE1, 0x7E, 0x61 },
|
|
+ { 0x27, 0x7C, 0x04, 0xE2, 0x85, 0x34, 0x84, 0xA4, 0xEB, 0xA9, 0x10, 0xAD, 0x33, 0x6D, 0x01, 0xB4, 0x77, 0xB6, 0x7C, 0xC2, 0x00, 0xC5, 0x9F, 0x3C, 0x8D, 0x77, 0xEE, 0xF8, 0x49, 0x4F, 0x29, 0xCD },
|
|
+ { 0x15, 0x6D, 0x57, 0x47, 0xD0, 0xC9, 0x9C, 0x7F, 0x27, 0x09, 0x7D, 0x7B, 0x7E, 0x00, 0x2B, 0x2E, 0x18, 0x5C, 0xB7, 0x2D, 0x8D, 0xD7, 0xEB, 0x42, 0x4A, 0x03, 0x21, 0x52, 0x81, 0x61, 0x21, 0x9F },
|
|
+ { 0x20, 0xDD, 0xD1, 0xED, 0x9B, 0x1C, 0xA8, 0x03, 0x94, 0x6D, 0x64, 0xA8, 0x3A, 0xE4, 0x65, 0x9D, 0xA6, 0x7F, 0xBA, 0x7A, 0x1A, 0x3E, 0xDD, 0xB1, 0xE1, 0x03, 0xC0, 0xF5, 0xE0, 0x3E, 0x3A, 0x2C },
|
|
+ { 0xF0, 0xAF, 0x60, 0x4D, 0x3D, 0xAB, 0xBF, 0x9A, 0x0F, 0x2A, 0x7D, 0x3D, 0xDA, 0x6B, 0xD3, 0x8B, 0xBA, 0x72, 0xC6, 0xD0, 0x9B, 0xE4, 0x94, 0xFC, 0xEF, 0x71, 0x3F, 0xF1, 0x01, 0x89, 0xB6, 0xE6 },
|
|
+ { 0x98, 0x02, 0xBB, 0x87, 0xDE, 0xF4, 0xCC, 0x10, 0xC4, 0xA5, 0xFD, 0x49, 0xAA, 0x58, 0xDF, 0xE2, 0xF3, 0xFD, 0xDB, 0x46, 0xB4, 0x70, 0x88, 0x14, 0xEA, 0xD8, 0x1D, 0x23, 0xBA, 0x95, 0x13, 0x9B },
|
|
+ { 0x4F, 0x8C, 0xE1, 0xE5, 0x1D, 0x2F, 0xE7, 0xF2, 0x40, 0x43, 0xA9, 0x04, 0xD8, 0x98, 0xEB, 0xFC, 0x91, 0x97, 0x54, 0x18, 0x75, 0x34, 0x13, 0xAA, 0x09, 0x9B, 0x79, 0x5E, 0xCB, 0x35, 0xCE, 0xDB },
|
|
+ { 0xBD, 0xDC, 0x65, 0x14, 0xD7, 0xEE, 0x6A, 0xCE, 0x0A, 0x4A, 0xC1, 0xD0, 0xE0, 0x68, 0x11, 0x22, 0x88, 0xCB, 0xCF, 0x56, 0x04, 0x54, 0x64, 0x27, 0x05, 0x63, 0x01, 0x77, 0xCB, 0xA6, 0x08, 0xBD },
|
|
+ { 0xD6, 0x35, 0x99, 0x4F, 0x62, 0x91, 0x51, 0x7B, 0x02, 0x81, 0xFF, 0xDD, 0x49, 0x6A, 0xFA, 0x86, 0x27, 0x12, 0xE5, 0xB3, 0xC4, 0xE5, 0x2E, 0x4C, 0xD5, 0xFD, 0xAE, 0x8C, 0x0E, 0x72, 0xFB, 0x08 },
|
|
+ { 0x87, 0x8D, 0x9C, 0xA6, 0x00, 0xCF, 0x87, 0xE7, 0x69, 0xCC, 0x30, 0x5C, 0x1B, 0x35, 0x25, 0x51, 0x86, 0x61, 0x5A, 0x73, 0xA0, 0xDA, 0x61, 0x3B, 0x5F, 0x1C, 0x98, 0xDB, 0xF8, 0x12, 0x83, 0xEA },
|
|
+ { 0xA6, 0x4E, 0xBE, 0x5D, 0xC1, 0x85, 0xDE, 0x9F, 0xDD, 0xE7, 0x60, 0x7B, 0x69, 0x98, 0x70, 0x2E, 0xB2, 0x34, 0x56, 0x18, 0x49, 0x57, 0x30, 0x7D, 0x2F, 0xA7, 0x2E, 0x87, 0xA4, 0x77, 0x02, 0xD6 },
|
|
+ { 0xCE, 0x50, 0xEA, 0xB7, 0xB5, 0xEB, 0x52, 0xBD, 0xC9, 0xAD, 0x8E, 0x5A, 0x48, 0x0A, 0xB7, 0x80, 0xCA, 0x93, 0x20, 0xE4, 0x43, 0x60, 0xB1, 0xFE, 0x37, 0xE0, 0x3F, 0x2F, 0x7A, 0xD7, 0xDE, 0x01 },
|
|
+ { 0xEE, 0xDD, 0xB7, 0xC0, 0xDB, 0x6E, 0x30, 0xAB, 0xE6, 0x6D, 0x79, 0xE3, 0x27, 0x51, 0x1E, 0x61, 0xFC, 0xEB, 0xBC, 0x29, 0xF1, 0x59, 0xB4, 0x0A, 0x86, 0xB0, 0x46, 0xEC, 0xF0, 0x51, 0x38, 0x23 },
|
|
+ { 0x78, 0x7F, 0xC9, 0x34, 0x40, 0xC1, 0xEC, 0x96, 0xB5, 0xAD, 0x01, 0xC1, 0x6C, 0xF7, 0x79, 0x16, 0xA1, 0x40, 0x5F, 0x94, 0x26, 0x35, 0x6E, 0xC9, 0x21, 0xD8, 0xDF, 0xF3, 0xEA, 0x63, 0xB7, 0xE0 },
|
|
+ { 0x7F, 0x0D, 0x5E, 0xAB, 0x47, 0xEE, 0xFD, 0xA6, 0x96, 0xC0, 0xBF, 0x0F, 0xBF, 0x86, 0xAB, 0x21, 0x6F, 0xCE, 0x46, 0x1E, 0x93, 0x03, 0xAB, 0xA6, 0xAC, 0x37, 0x41, 0x20, 0xE8, 0x90, 0xE8, 0xDF },
|
|
+ { 0xB6, 0x80, 0x04, 0xB4, 0x2F, 0x14, 0xAD, 0x02, 0x9F, 0x4C, 0x2E, 0x03, 0xB1, 0xD5, 0xEB, 0x76, 0xD5, 0x71, 0x60, 0xE2, 0x64, 0x76, 0xD2, 0x11, 0x31, 0xBE, 0xF2, 0x0A, 0xDA, 0x7D, 0x27, 0xF4 },
|
|
+ { 0xB0, 0xC4, 0xEB, 0x18, 0xAE, 0x25, 0x0B, 0x51, 0xA4, 0x13, 0x82, 0xEA, 0xD9, 0x2D, 0x0D, 0xC7, 0x45, 0x5F, 0x93, 0x79, 0xFC, 0x98, 0x84, 0x42, 0x8E, 0x47, 0x70, 0x60, 0x8D, 0xB0, 0xFA, 0xEC },
|
|
+ { 0xF9, 0x2B, 0x7A, 0x87, 0x0C, 0x05, 0x9F, 0x4D, 0x46, 0x46, 0x4C, 0x82, 0x4E, 0xC9, 0x63, 0x55, 0x14, 0x0B, 0xDC, 0xE6, 0x81, 0x32, 0x2C, 0xC3, 0xA9, 0x92, 0xFF, 0x10, 0x3E, 0x3F, 0xEA, 0x52 },
|
|
+ { 0x53, 0x64, 0x31, 0x26, 0x14, 0x81, 0x33, 0x98, 0xCC, 0x52, 0x5D, 0x4C, 0x4E, 0x14, 0x6E, 0xDE, 0xB3, 0x71, 0x26, 0x5F, 0xBA, 0x19, 0x13, 0x3A, 0x2C, 0x3D, 0x21, 0x59, 0x29, 0x8A, 0x17, 0x42 },
|
|
+ { 0xF6, 0x62, 0x0E, 0x68, 0xD3, 0x7F, 0xB2, 0xAF, 0x50, 0x00, 0xFC, 0x28, 0xE2, 0x3B, 0x83, 0x22, 0x97, 0xEC, 0xD8, 0xBC, 0xE9, 0x9E, 0x8B, 0xE4, 0xD0, 0x4E, 0x85, 0x30, 0x9E, 0x3D, 0x33, 0x74 },
|
|
+ { 0x53, 0x16, 0xA2, 0x79, 0x69, 0xD7, 0xFE, 0x04, 0xFF, 0x27, 0xB2, 0x83, 0x96, 0x1B, 0xFF, 0xC3, 0xBF, 0x5D, 0xFB, 0x32, 0xFB, 0x6A, 0x89, 0xD1, 0x01, 0xC6, 0xC3, 0xB1, 0x93, 0x7C, 0x28, 0x71 },
|
|
+ { 0x81, 0xD1, 0x66, 0x4F, 0xDF, 0x3C, 0xB3, 0x3C, 0x24, 0xEE, 0xBA, 0xC0, 0xBD, 0x64, 0x24, 0x4B, 0x77, 0xC4, 0xAB, 0xEA, 0x90, 0xBB, 0xE8, 0xB5, 0xEE, 0x0B, 0x2A, 0xAF, 0xCF, 0x2D, 0x6A, 0x53 },
|
|
+ { 0x34, 0x57, 0x82, 0xF2, 0x95, 0xB0, 0x88, 0x03, 0x52, 0xE9, 0x24, 0xA0, 0x46, 0x7B, 0x5F, 0xBC, 0x3E, 0x8F, 0x3B, 0xFB, 0xC3, 0xC7, 0xE4, 0x8B, 0x67, 0x09, 0x1F, 0xB5, 0xE8, 0x0A, 0x94, 0x42 },
|
|
+ { 0x79, 0x41, 0x11, 0xEA, 0x6C, 0xD6, 0x5E, 0x31, 0x1F, 0x74, 0xEE, 0x41, 0xD4, 0x76, 0xCB, 0x63, 0x2C, 0xE1, 0xE4, 0xB0, 0x51, 0xDC, 0x1D, 0x9E, 0x9D, 0x06, 0x1A, 0x19, 0xE1, 0xD0, 0xBB, 0x49 },
|
|
+ { 0x2A, 0x85, 0xDA, 0xF6, 0x13, 0x88, 0x16, 0xB9, 0x9B, 0xF8, 0xD0, 0x8B, 0xA2, 0x11, 0x4B, 0x7A, 0xB0, 0x79, 0x75, 0xA7, 0x84, 0x20, 0xC1, 0xA3, 0xB0, 0x6A, 0x77, 0x7C, 0x22, 0xDD, 0x8B, 0xCB },
|
|
+ { 0x89, 0xB0, 0xD5, 0xF2, 0x89, 0xEC, 0x16, 0x40, 0x1A, 0x06, 0x9A, 0x96, 0x0D, 0x0B, 0x09, 0x3E, 0x62, 0x5D, 0xA3, 0xCF, 0x41, 0xEE, 0x29, 0xB5, 0x9B, 0x93, 0x0C, 0x58, 0x20, 0x14, 0x54, 0x55 },
|
|
+ { 0xD0, 0xFD, 0xCB, 0x54, 0x39, 0x43, 0xFC, 0x27, 0xD2, 0x08, 0x64, 0xF5, 0x21, 0x81, 0x47, 0x1B, 0x94, 0x2C, 0xC7, 0x7C, 0xA6, 0x75, 0xBC, 0xB3, 0x0D, 0xF3, 0x1D, 0x35, 0x8E, 0xF7, 0xB1, 0xEB },
|
|
+ { 0xB1, 0x7E, 0xA8, 0xD7, 0x70, 0x63, 0xC7, 0x09, 0xD4, 0xDC, 0x6B, 0x87, 0x94, 0x13, 0xC3, 0x43, 0xE3, 0x79, 0x0E, 0x9E, 0x62, 0xCA, 0x85, 0xB7, 0x90, 0x0B, 0x08, 0x6F, 0x6B, 0x75, 0xC6, 0x72 },
|
|
+ { 0xE7, 0x1A, 0x3E, 0x2C, 0x27, 0x4D, 0xB8, 0x42, 0xD9, 0x21, 0x14, 0xF2, 0x17, 0xE2, 0xC0, 0xEA, 0xC8, 0xB4, 0x50, 0x93, 0xFD, 0xFD, 0x9D, 0xF4, 0xCA, 0x71, 0x62, 0x39, 0x48, 0x62, 0xD5, 0x01 },
|
|
+ { 0xC0, 0x47, 0x67, 0x59, 0xAB, 0x7A, 0xA3, 0x33, 0x23, 0x4F, 0x6B, 0x44, 0xF5, 0xFD, 0x85, 0x83, 0x90, 0xEC, 0x23, 0x69, 0x4C, 0x62, 0x2C, 0xB9, 0x86, 0xE7, 0x69, 0xC7, 0x8E, 0xDD, 0x73, 0x3E },
|
|
+ { 0x9A, 0xB8, 0xEA, 0xBB, 0x14, 0x16, 0x43, 0x4D, 0x85, 0x39, 0x13, 0x41, 0xD5, 0x69, 0x93, 0xC5, 0x54, 0x58, 0x16, 0x7D, 0x44, 0x18, 0xB1, 0x9A, 0x0F, 0x2A, 0xD8, 0xB7, 0x9A, 0x83, 0xA7, 0x5B },
|
|
+ { 0x79, 0x92, 0xD0, 0xBB, 0xB1, 0x5E, 0x23, 0x82, 0x6F, 0x44, 0x3E, 0x00, 0x50, 0x5D, 0x68, 0xD3, 0xED, 0x73, 0x72, 0x99, 0x5A, 0x5C, 0x3E, 0x49, 0x86, 0x54, 0x10, 0x2F, 0xBC, 0xD0, 0x96, 0x4E },
|
|
+ { 0xC0, 0x21, 0xB3, 0x00, 0x85, 0x15, 0x14, 0x35, 0xDF, 0x33, 0xB0, 0x07, 0xCC, 0xEC, 0xC6, 0x9D, 0xF1, 0x26, 0x9F, 0x39, 0xBA, 0x25, 0x09, 0x2B, 0xED, 0x59, 0xD9, 0x32, 0xAC, 0x0F, 0xDC, 0x28 },
|
|
+ { 0x91, 0xA2, 0x5E, 0xC0, 0xEC, 0x0D, 0x9A, 0x56, 0x7F, 0x89, 0xC4, 0xBF, 0xE1, 0xA6, 0x5A, 0x0E, 0x43, 0x2D, 0x07, 0x06, 0x4B, 0x41, 0x90, 0xE2, 0x7D, 0xFB, 0x81, 0x90, 0x1F, 0xD3, 0x13, 0x9B },
|
|
+ { 0x59, 0x50, 0xD3, 0x9A, 0x23, 0xE1, 0x54, 0x5F, 0x30, 0x12, 0x70, 0xAA, 0x1A, 0x12, 0xF2, 0xE6, 0xC4, 0x53, 0x77, 0x6E, 0x4D, 0x63, 0x55, 0xDE, 0x42, 0x5C, 0xC1, 0x53, 0xF9, 0x81, 0x88, 0x67 },
|
|
+ { 0xD7, 0x9F, 0x14, 0x72, 0x0C, 0x61, 0x0A, 0xF1, 0x79, 0xA3, 0x76, 0x5D, 0x4B, 0x7C, 0x09, 0x68, 0xF9, 0x77, 0x96, 0x2D, 0xBF, 0x65, 0x5B, 0x52, 0x12, 0x72, 0xB6, 0xF1, 0xE1, 0x94, 0x48, 0x8E },
|
|
+ { 0xE9, 0x53, 0x1B, 0xFC, 0x8B, 0x02, 0x99, 0x5A, 0xEA, 0xA7, 0x5B, 0xA2, 0x70, 0x31, 0xFA, 0xDB, 0xCB, 0xF4, 0xA0, 0xDA, 0xB8, 0x96, 0x1D, 0x92, 0x96, 0xCD, 0x7E, 0x84, 0xD2, 0x5D, 0x60, 0x06 },
|
|
+ { 0x34, 0xE9, 0xC2, 0x6A, 0x01, 0xD7, 0xF1, 0x61, 0x81, 0xB4, 0x54, 0xA9, 0xD1, 0x62, 0x3C, 0x23, 0x3C, 0xB9, 0x9D, 0x31, 0xC6, 0x94, 0x65, 0x6E, 0x94, 0x13, 0xAC, 0xA3, 0xE9, 0x18, 0x69, 0x2F },
|
|
+ { 0xD9, 0xD7, 0x42, 0x2F, 0x43, 0x7B, 0xD4, 0x39, 0xDD, 0xD4, 0xD8, 0x83, 0xDA, 0xE2, 0xA0, 0x83, 0x50, 0x17, 0x34, 0x14, 0xBE, 0x78, 0x15, 0x51, 0x33, 0xFF, 0xF1, 0x96, 0x4C, 0x3D, 0x79, 0x72 },
|
|
+ { 0x4A, 0xEE, 0x0C, 0x7A, 0xAF, 0x07, 0x54, 0x14, 0xFF, 0x17, 0x93, 0xEA, 0xD7, 0xEA, 0xCA, 0x60, 0x17, 0x75, 0xC6, 0x15, 0xDB, 0xD6, 0x0B, 0x64, 0x0B, 0x0A, 0x9F, 0x0C, 0xE5, 0x05, 0xD4, 0x35 },
|
|
+ { 0x6B, 0xFD, 0xD1, 0x54, 0x59, 0xC8, 0x3B, 0x99, 0xF0, 0x96, 0xBF, 0xB4, 0x9E, 0xE8, 0x7B, 0x06, 0x3D, 0x69, 0xC1, 0x97, 0x4C, 0x69, 0x28, 0xAC, 0xFC, 0xFB, 0x40, 0x99, 0xF8, 0xC4, 0xEF, 0x67 },
|
|
+ { 0x9F, 0xD1, 0xC4, 0x08, 0xFD, 0x75, 0xC3, 0x36, 0x19, 0x3A, 0x2A, 0x14, 0xD9, 0x4F, 0x6A, 0xF5, 0xAD, 0xF0, 0x50, 0xB8, 0x03, 0x87, 0xB4, 0xB0, 0x10, 0xFB, 0x29, 0xF4, 0xCC, 0x72, 0x70, 0x7C },
|
|
+ { 0x13, 0xC8, 0x84, 0x80, 0xA5, 0xD0, 0x0D, 0x6C, 0x8C, 0x7A, 0xD2, 0x11, 0x0D, 0x76, 0xA8, 0x2D, 0x9B, 0x70, 0xF4, 0xFA, 0x66, 0x96, 0xD4, 0xE5, 0xDD, 0x42, 0xA0, 0x66, 0xDC, 0xAF, 0x99, 0x20 },
|
|
+ { 0x82, 0x0E, 0x72, 0x5E, 0xE2, 0x5F, 0xE8, 0xFD, 0x3A, 0x8D, 0x5A, 0xBE, 0x4C, 0x46, 0xC3, 0xBA, 0x88, 0x9D, 0xE6, 0xFA, 0x91, 0x91, 0xAA, 0x22, 0xBA, 0x67, 0xD5, 0x70, 0x54, 0x21, 0x54, 0x2B },
|
|
+ { 0x32, 0xD9, 0x3A, 0x0E, 0xB0, 0x2F, 0x42, 0xFB, 0xBC, 0xAF, 0x2B, 0xAD, 0x00, 0x85, 0xB2, 0x82, 0xE4, 0x60, 0x46, 0xA4, 0xDF, 0x7A, 0xD1, 0x06, 0x57, 0xC9, 0xD6, 0x47, 0x63, 0x75, 0xB9, 0x3E },
|
|
+ { 0xAD, 0xC5, 0x18, 0x79, 0x05, 0xB1, 0x66, 0x9C, 0xD8, 0xEC, 0x9C, 0x72, 0x1E, 0x19, 0x53, 0x78, 0x6B, 0x9D, 0x89, 0xA9, 0xBA, 0xE3, 0x07, 0x80, 0xF1, 0xE1, 0xEA, 0xB2, 0x4A, 0x00, 0x52, 0x3C },
|
|
+ { 0xE9, 0x07, 0x56, 0xFF, 0x7F, 0x9A, 0xD8, 0x10, 0xB2, 0x39, 0xA1, 0x0C, 0xED, 0x2C, 0xF9, 0xB2, 0x28, 0x43, 0x54, 0xC1, 0xF8, 0xC7, 0xE0, 0xAC, 0xCC, 0x24, 0x61, 0xDC, 0x79, 0x6D, 0x6E, 0x89 },
|
|
+ { 0x12, 0x51, 0xF7, 0x6E, 0x56, 0x97, 0x84, 0x81, 0x87, 0x53, 0x59, 0x80, 0x1D, 0xB5, 0x89, 0xA0, 0xB2, 0x2F, 0x86, 0xD8, 0xD6, 0x34, 0xDC, 0x04, 0x50, 0x6F, 0x32, 0x2E, 0xD7, 0x8F, 0x17, 0xE8 },
|
|
+ { 0x3A, 0xFA, 0x89, 0x9F, 0xD9, 0x80, 0xE7, 0x3E, 0xCB, 0x7F, 0x4D, 0x8B, 0x8F, 0x29, 0x1D, 0xC9, 0xAF, 0x79, 0x6B, 0xC6, 0x5D, 0x27, 0xF9, 0x74, 0xC6, 0xF1, 0x93, 0xC9, 0x19, 0x1A, 0x09, 0xFD },
|
|
+ { 0xAA, 0x30, 0x5B, 0xE2, 0x6E, 0x5D, 0xED, 0xDC, 0x3C, 0x10, 0x10, 0xCB, 0xC2, 0x13, 0xF9, 0x5F, 0x05, 0x1C, 0x78, 0x5C, 0x5B, 0x43, 0x1E, 0x6A, 0x7C, 0xD0, 0x48, 0xF1, 0x61, 0x78, 0x75, 0x28 },
|
|
+ { 0x8E, 0xA1, 0x88, 0x4F, 0xF3, 0x2E, 0x9D, 0x10, 0xF0, 0x39, 0xB4, 0x07, 0xD0, 0xD4, 0x4E, 0x7E, 0x67, 0x0A, 0xBD, 0x88, 0x4A, 0xEE, 0xE0, 0xFB, 0x75, 0x7A, 0xE9, 0x4E, 0xAA, 0x97, 0x37, 0x3D },
|
|
+ { 0xD4, 0x82, 0xB2, 0x15, 0x5D, 0x4D, 0xEC, 0x6B, 0x47, 0x36, 0xA1, 0xF1, 0x61, 0x7B, 0x53, 0xAA, 0xA3, 0x73, 0x10, 0x27, 0x7D, 0x3F, 0xEF, 0x0C, 0x37, 0xAD, 0x41, 0x76, 0x8F, 0xC2, 0x35, 0xB4 },
|
|
+ { 0x4D, 0x41, 0x39, 0x71, 0x38, 0x7E, 0x7A, 0x88, 0x98, 0xA8, 0xDC, 0x2A, 0x27, 0x50, 0x07, 0x78, 0x53, 0x9E, 0xA2, 0x14, 0xA2, 0xDF, 0xE9, 0xB3, 0xD7, 0xE8, 0xEB, 0xDC, 0xE5, 0xCF, 0x3D, 0xB3 },
|
|
+ { 0x69, 0x6E, 0x5D, 0x46, 0xE6, 0xC5, 0x7E, 0x87, 0x96, 0xE4, 0x73, 0x5D, 0x08, 0x91, 0x6E, 0x0B, 0x79, 0x29, 0xB3, 0xCF, 0x29, 0x8C, 0x29, 0x6D, 0x22, 0xE9, 0xD3, 0x01, 0x96, 0x53, 0x37, 0x1C },
|
|
+ { 0x1F, 0x56, 0x47, 0xC1, 0xD3, 0xB0, 0x88, 0x22, 0x88, 0x85, 0x86, 0x5C, 0x89, 0x40, 0x90, 0x8B, 0xF4, 0x0D, 0x1A, 0x82, 0x72, 0x82, 0x19, 0x73, 0xB1, 0x60, 0x00, 0x8E, 0x7A, 0x3C, 0xE2, 0xEB },
|
|
+ { 0xB6, 0xE7, 0x6C, 0x33, 0x0F, 0x02, 0x1A, 0x5B, 0xDA, 0x65, 0x87, 0x50, 0x10, 0xB0, 0xED, 0xF0, 0x91, 0x26, 0xC0, 0xF5, 0x10, 0xEA, 0x84, 0x90, 0x48, 0x19, 0x20, 0x03, 0xAE, 0xF4, 0xC6, 0x1C },
|
|
+ { 0x3C, 0xD9, 0x52, 0xA0, 0xBE, 0xAD, 0xA4, 0x1A, 0xBB, 0x42, 0x4C, 0xE4, 0x7F, 0x94, 0xB4, 0x2B, 0xE6, 0x4E, 0x1F, 0xFB, 0x0F, 0xD0, 0x78, 0x22, 0x76, 0x80, 0x79, 0x46, 0xD0, 0xD0, 0xBC, 0x55 },
|
|
+ { 0x98, 0xD9, 0x26, 0x77, 0x43, 0x9B, 0x41, 0xB7, 0xBB, 0x51, 0x33, 0x12, 0xAF, 0xB9, 0x2B, 0xCC, 0x8E, 0xE9, 0x68, 0xB2, 0xE3, 0xB2, 0x38, 0xCE, 0xCB, 0x9B, 0x0F, 0x34, 0xC9, 0xBB, 0x63, 0xD0 },
|
|
+ { 0xEC, 0xBC, 0xA2, 0xCF, 0x08, 0xAE, 0x57, 0xD5, 0x17, 0xAD, 0x16, 0x15, 0x8A, 0x32, 0xBF, 0xA7, 0xDC, 0x03, 0x82, 0xEA, 0xED, 0xA1, 0x28, 0xE9, 0x18, 0x86, 0x73, 0x4C, 0x24, 0xA0, 0xB2, 0x9D },
|
|
+ { 0x94, 0x2C, 0xC7, 0xC0, 0xB5, 0x2E, 0x2B, 0x16, 0xA4, 0xB8, 0x9F, 0xA4, 0xFC, 0x7E, 0x0B, 0xF6, 0x09, 0xE2, 0x9A, 0x08, 0xC1, 0xA8, 0x54, 0x34, 0x52, 0xB7, 0x7C, 0x7B, 0xFD, 0x11, 0xBB, 0x28 },
|
|
+ { 0x8A, 0x06, 0x5D, 0x8B, 0x61, 0xA0, 0xDF, 0xFB, 0x17, 0x0D, 0x56, 0x27, 0x73, 0x5A, 0x76, 0xB0, 0xE9, 0x50, 0x60, 0x37, 0x80, 0x8C, 0xBA, 0x16, 0xC3, 0x45, 0x00, 0x7C, 0x9F, 0x79, 0xCF, 0x8F },
|
|
+ { 0x1B, 0x9F, 0xA1, 0x97, 0x14, 0x65, 0x9C, 0x78, 0xFF, 0x41, 0x38, 0x71, 0x84, 0x92, 0x15, 0x36, 0x10, 0x29, 0xAC, 0x80, 0x2B, 0x1C, 0xBC, 0xD5, 0x4E, 0x40, 0x8B, 0xD8, 0x72, 0x87, 0xF8, 0x1F },
|
|
+ { 0x8D, 0xAB, 0x07, 0x1B, 0xCD, 0x6C, 0x72, 0x92, 0xA9, 0xEF, 0x72, 0x7B, 0x4A, 0xE0, 0xD8, 0x67, 0x13, 0x30, 0x1D, 0xA8, 0x61, 0x8D, 0x9A, 0x48, 0xAD, 0xCE, 0x55, 0xF3, 0x03, 0xA8, 0x69, 0xA1 },
|
|
+ { 0x82, 0x53, 0xE3, 0xE7, 0xC7, 0xB6, 0x84, 0xB9, 0xCB, 0x2B, 0xEB, 0x01, 0x4C, 0xE3, 0x30, 0xFF, 0x3D, 0x99, 0xD1, 0x7A, 0xBB, 0xDB, 0xAB, 0xE4, 0xF4, 0xD6, 0x74, 0xDE, 0xD5, 0x3F, 0xFC, 0x6B },
|
|
+ { 0xF1, 0x95, 0xF3, 0x21, 0xE9, 0xE3, 0xD6, 0xBD, 0x7D, 0x07, 0x45, 0x04, 0xDD, 0x2A, 0xB0, 0xE6, 0x24, 0x1F, 0x92, 0xE7, 0x84, 0xB1, 0xAA, 0x27, 0x1F, 0xF6, 0x48, 0xB1, 0xCA, 0xB6, 0xD7, 0xF6 },
|
|
+ { 0x27, 0xE4, 0xCC, 0x72, 0x09, 0x0F, 0x24, 0x12, 0x66, 0x47, 0x6A, 0x7C, 0x09, 0x49, 0x5F, 0x2D, 0xB1, 0x53, 0xD5, 0xBC, 0xBD, 0x76, 0x19, 0x03, 0xEF, 0x79, 0x27, 0x5E, 0xC5, 0x6B, 0x2E, 0xD8 },
|
|
+ { 0x89, 0x9C, 0x24, 0x05, 0x78, 0x8E, 0x25, 0xB9, 0x9A, 0x18, 0x46, 0x35, 0x5E, 0x64, 0x6D, 0x77, 0xCF, 0x40, 0x00, 0x83, 0x41, 0x5F, 0x7D, 0xC5, 0xAF, 0xE6, 0x9D, 0x6E, 0x17, 0xC0, 0x00, 0x23 },
|
|
+ { 0xA5, 0x9B, 0x78, 0xC4, 0x90, 0x57, 0x44, 0x07, 0x6B, 0xFE, 0xE8, 0x94, 0xDE, 0x70, 0x7D, 0x4F, 0x12, 0x0B, 0x5C, 0x68, 0x93, 0xEA, 0x04, 0x00, 0x29, 0x7D, 0x0B, 0xB8, 0x34, 0x72, 0x76, 0x32 },
|
|
+ { 0x59, 0xDC, 0x78, 0xB1, 0x05, 0x64, 0x97, 0x07, 0xA2, 0xBB, 0x44, 0x19, 0xC4, 0x8F, 0x00, 0x54, 0x00, 0xD3, 0x97, 0x3D, 0xE3, 0x73, 0x66, 0x10, 0x23, 0x04, 0x35, 0xB1, 0x04, 0x24, 0xB2, 0x4F },
|
|
+ { 0xC0, 0x14, 0x9D, 0x1D, 0x7E, 0x7A, 0x63, 0x53, 0xA6, 0xD9, 0x06, 0xEF, 0xE7, 0x28, 0xF2, 0xF3, 0x29, 0xFE, 0x14, 0xA4, 0x14, 0x9A, 0x3E, 0xA7, 0x76, 0x09, 0xBC, 0x42, 0xB9, 0x75, 0xDD, 0xFA },
|
|
+ { 0xA3, 0x2F, 0x24, 0x14, 0x74, 0xA6, 0xC1, 0x69, 0x32, 0xE9, 0x24, 0x3B, 0xE0, 0xCF, 0x09, 0xBC, 0xDC, 0x7E, 0x0C, 0xA0, 0xE7, 0xA6, 0xA1, 0xB9, 0xB1, 0xA0, 0xF0, 0x1E, 0x41, 0x50, 0x23, 0x77 },
|
|
+ { 0xB2, 0x39, 0xB2, 0xE4, 0xF8, 0x18, 0x41, 0x36, 0x1C, 0x13, 0x39, 0xF6, 0x8E, 0x2C, 0x35, 0x9F, 0x92, 0x9A, 0xF9, 0xAD, 0x9F, 0x34, 0xE0, 0x1A, 0xAB, 0x46, 0x31, 0xAD, 0x6D, 0x55, 0x00, 0xB0 },
|
|
+ { 0x85, 0xFB, 0x41, 0x9C, 0x70, 0x02, 0xA3, 0xE0, 0xB4, 0xB6, 0xEA, 0x09, 0x3B, 0x4C, 0x1A, 0xC6, 0x93, 0x66, 0x45, 0xB6, 0x5D, 0xAC, 0x5A, 0xC1, 0x5A, 0x85, 0x28, 0xB7, 0xB9, 0x4C, 0x17, 0x54 },
|
|
+ { 0x96, 0x19, 0x72, 0x06, 0x25, 0xF1, 0x90, 0xB9, 0x3A, 0x3F, 0xAD, 0x18, 0x6A, 0xB3, 0x14, 0x18, 0x96, 0x33, 0xC0, 0xD3, 0xA0, 0x1E, 0x6F, 0x9B, 0xC8, 0xC4, 0xA8, 0xF8, 0x2F, 0x38, 0x3D, 0xBF },
|
|
+ { 0x7D, 0x62, 0x0D, 0x90, 0xFE, 0x69, 0xFA, 0x46, 0x9A, 0x65, 0x38, 0x38, 0x89, 0x70, 0xA1, 0xAA, 0x09, 0xBB, 0x48, 0xA2, 0xD5, 0x9B, 0x34, 0x7B, 0x97, 0xE8, 0xCE, 0x71, 0xF4, 0x8C, 0x7F, 0x46 },
|
|
+ { 0x29, 0x43, 0x83, 0x56, 0x85, 0x96, 0xFB, 0x37, 0xC7, 0x5B, 0xBA, 0xCD, 0x97, 0x9C, 0x5F, 0xF6, 0xF2, 0x0A, 0x55, 0x6B, 0xF8, 0x87, 0x9C, 0xC7, 0x29, 0x24, 0x85, 0x5D, 0xF9, 0xB8, 0x24, 0x0E },
|
|
+ { 0x16, 0xB1, 0x8A, 0xB3, 0x14, 0x35, 0x9C, 0x2B, 0x83, 0x3C, 0x1C, 0x69, 0x86, 0xD4, 0x8C, 0x55, 0xA9, 0xFC, 0x97, 0xCD, 0xE9, 0xA3, 0xC1, 0xF1, 0x0A, 0x31, 0x77, 0x14, 0x0F, 0x73, 0xF7, 0x38 },
|
|
+ { 0x8C, 0xBB, 0xDD, 0x14, 0xBC, 0x33, 0xF0, 0x4C, 0xF4, 0x58, 0x13, 0xE4, 0xA1, 0x53, 0xA2, 0x73, 0xD3, 0x6A, 0xDA, 0xD5, 0xCE, 0x71, 0xF4, 0x99, 0xEE, 0xB8, 0x7F, 0xB8, 0xAC, 0x63, 0xB7, 0x29 },
|
|
+ { 0x69, 0xC9, 0xA4, 0x98, 0xDB, 0x17, 0x4E, 0xCA, 0xEF, 0xCC, 0x5A, 0x3A, 0xC9, 0xFD, 0xED, 0xF0, 0xF8, 0x13, 0xA5, 0xBE, 0xC7, 0x27, 0xF1, 0xE7, 0x75, 0xBA, 0xBD, 0xEC, 0x77, 0x18, 0x81, 0x6E },
|
|
+ { 0xB4, 0x62, 0xC3, 0xBE, 0x40, 0x44, 0x8F, 0x1D, 0x4F, 0x80, 0x62, 0x62, 0x54, 0xE5, 0x35, 0xB0, 0x8B, 0xC9, 0xCD, 0xCF, 0xF5, 0x99, 0xA7, 0x68, 0x57, 0x8D, 0x4B, 0x28, 0x81, 0xA8, 0xE3, 0xF0 },
|
|
+ { 0x55, 0x3E, 0x9D, 0x9C, 0x5F, 0x36, 0x0A, 0xC0, 0xB7, 0x4A, 0x7D, 0x44, 0xE5, 0xA3, 0x91, 0xDA, 0xD4, 0xCE, 0xD0, 0x3E, 0x0C, 0x24, 0x18, 0x3B, 0x7E, 0x8E, 0xCA, 0xBD, 0xF1, 0x71, 0x5A, 0x64 },
|
|
+ { 0x7A, 0x7C, 0x55, 0xA5, 0x6F, 0xA9, 0xAE, 0x51, 0xE6, 0x55, 0xE0, 0x19, 0x75, 0xD8, 0xA6, 0xFF, 0x4A, 0xE9, 0xE4, 0xB4, 0x86, 0xFC, 0xBE, 0x4E, 0xAC, 0x04, 0x45, 0x88, 0xF2, 0x45, 0xEB, 0xEA },
|
|
+ { 0x2A, 0xFD, 0xF3, 0xC8, 0x2A, 0xBC, 0x48, 0x67, 0xF5, 0xDE, 0x11, 0x12, 0x86, 0xC2, 0xB3, 0xBE, 0x7D, 0x6E, 0x48, 0x65, 0x7B, 0xA9, 0x23, 0xCF, 0xBF, 0x10, 0x1A, 0x6D, 0xFC, 0xF9, 0xDB, 0x9A },
|
|
+ { 0x41, 0x03, 0x7D, 0x2E, 0xDC, 0xDC, 0xE0, 0xC4, 0x9B, 0x7F, 0xB4, 0xA6, 0xAA, 0x09, 0x99, 0xCA, 0x66, 0x97, 0x6C, 0x74, 0x83, 0xAF, 0xE6, 0x31, 0xD4, 0xED, 0xA2, 0x83, 0x14, 0x4F, 0x6D, 0xFC },
|
|
+ { 0xC4, 0x46, 0x6F, 0x84, 0x97, 0xCA, 0x2E, 0xEB, 0x45, 0x83, 0xA0, 0xB0, 0x8E, 0x9D, 0x9A, 0xC7, 0x43, 0x95, 0x70, 0x9F, 0xDA, 0x10, 0x9D, 0x24, 0xF2, 0xE4, 0x46, 0x21, 0x96, 0x77, 0x9C, 0x5D },
|
|
+ { 0x75, 0xF6, 0x09, 0x33, 0x8A, 0xA6, 0x7D, 0x96, 0x9A, 0x2A, 0xE2, 0xA2, 0x36, 0x2B, 0x2D, 0xA9, 0xD7, 0x7C, 0x69, 0x5D, 0xFD, 0x1D, 0xF7, 0x22, 0x4A, 0x69, 0x01, 0xDB, 0x93, 0x2C, 0x33, 0x64 },
|
|
+ { 0x68, 0x60, 0x6C, 0xEB, 0x98, 0x9D, 0x54, 0x88, 0xFC, 0x7C, 0xF6, 0x49, 0xF3, 0xD7, 0xC2, 0x72, 0xEF, 0x05, 0x5D, 0xA1, 0xA9, 0x3F, 0xAE, 0xCD, 0x55, 0xFE, 0x06, 0xF6, 0x96, 0x70, 0x98, 0xCA },
|
|
+ { 0x44, 0x34, 0x6B, 0xDE, 0xB7, 0xE0, 0x52, 0xF6, 0x25, 0x50, 0x48, 0xF0, 0xD9, 0xB4, 0x2C, 0x42, 0x5B, 0xAB, 0x9C, 0x3D, 0xD2, 0x41, 0x68, 0x21, 0x2C, 0x3E, 0xCF, 0x1E, 0xBF, 0x34, 0xE6, 0xAE },
|
|
+ { 0x8E, 0x9C, 0xF6, 0xE1, 0xF3, 0x66, 0x47, 0x1F, 0x2A, 0xC7, 0xD2, 0xEE, 0x9B, 0x5E, 0x62, 0x66, 0xFD, 0xA7, 0x1F, 0x8F, 0x2E, 0x41, 0x09, 0xF2, 0x23, 0x7E, 0xD5, 0xF8, 0x81, 0x3F, 0xC7, 0x18 },
|
|
+ { 0x84, 0xBB, 0xEB, 0x84, 0x06, 0xD2, 0x50, 0x95, 0x1F, 0x8C, 0x1B, 0x3E, 0x86, 0xA7, 0xC0, 0x10, 0x08, 0x29, 0x21, 0x83, 0x3D, 0xFD, 0x95, 0x55, 0xA2, 0xF9, 0x09, 0xB1, 0x08, 0x6E, 0xB4, 0xB8 },
|
|
+ { 0xEE, 0x66, 0x6F, 0x3E, 0xEF, 0x0F, 0x7E, 0x2A, 0x9C, 0x22, 0x29, 0x58, 0xC9, 0x7E, 0xAF, 0x35, 0xF5, 0x1C, 0xED, 0x39, 0x3D, 0x71, 0x44, 0x85, 0xAB, 0x09, 0xA0, 0x69, 0x34, 0x0F, 0xDF, 0x88 },
|
|
+ { 0xC1, 0x53, 0xD3, 0x4A, 0x65, 0xC4, 0x7B, 0x4A, 0x62, 0xC5, 0xCA, 0xCF, 0x24, 0x01, 0x09, 0x75, 0xD0, 0x35, 0x6B, 0x2F, 0x32, 0xC8, 0xF5, 0xDA, 0x53, 0x0D, 0x33, 0x88, 0x16, 0xAD, 0x5D, 0xE6 },
|
|
+ { 0x9F, 0xC5, 0x45, 0x01, 0x09, 0xE1, 0xB7, 0x79, 0xF6, 0xC7, 0xAE, 0x79, 0xD5, 0x6C, 0x27, 0x63, 0x5C, 0x8D, 0xD4, 0x26, 0xC5, 0xA9, 0xD5, 0x4E, 0x25, 0x78, 0xDB, 0x98, 0x9B, 0x8C, 0x3B, 0x4E },
|
|
+ { 0xD1, 0x2B, 0xF3, 0x73, 0x2E, 0xF4, 0xAF, 0x5C, 0x22, 0xFA, 0x90, 0x35, 0x6A, 0xF8, 0xFC, 0x50, 0xFC, 0xB4, 0x0F, 0x8F, 0x2E, 0xA5, 0xC8, 0x59, 0x47, 0x37, 0xA3, 0xB3, 0xD5, 0xAB, 0xDB, 0xD7 },
|
|
+ { 0x11, 0x03, 0x0B, 0x92, 0x89, 0xBB, 0xA5, 0xAF, 0x65, 0x26, 0x06, 0x72, 0xAB, 0x6F, 0xEE, 0x88, 0xB8, 0x74, 0x20, 0xAC, 0xEF, 0x4A, 0x17, 0x89, 0xA2, 0x07, 0x3B, 0x7E, 0xC2, 0xF2, 0xA0, 0x9E },
|
|
+ { 0x69, 0xCB, 0x19, 0x2B, 0x84, 0x44, 0x00, 0x5C, 0x8C, 0x0C, 0xEB, 0x12, 0xC8, 0x46, 0x86, 0x07, 0x68, 0x18, 0x8C, 0xDA, 0x0A, 0xEC, 0x27, 0xA9, 0xC8, 0xA5, 0x5C, 0xDE, 0xE2, 0x12, 0x36, 0x32 },
|
|
+ { 0xDB, 0x44, 0x4C, 0x15, 0x59, 0x7B, 0x5F, 0x1A, 0x03, 0xD1, 0xF9, 0xED, 0xD1, 0x6E, 0x4A, 0x9F, 0x43, 0xA6, 0x67, 0xCC, 0x27, 0x51, 0x75, 0xDF, 0xA2, 0xB7, 0x04, 0xE3, 0xBB, 0x1A, 0x9B, 0x83 },
|
|
+ { 0x3F, 0xB7, 0x35, 0x06, 0x1A, 0xBC, 0x51, 0x9D, 0xFE, 0x97, 0x9E, 0x54, 0xC1, 0xEE, 0x5B, 0xFA, 0xD0, 0xA9, 0xD8, 0x58, 0xB3, 0x31, 0x5B, 0xAD, 0x34, 0xBD, 0xE9, 0x99, 0xEF, 0xD7, 0x24, 0xDD }
|
|
+};
|
|
+
|
|
+bool blake2s_selftest(void)
|
|
+{
|
|
+ u8 key[BLAKE2S_KEYBYTES];
|
|
+ u8 buf[ARRAY_SIZE(blake2s_testvecs)];
|
|
+ u8 hash[BLAKE2S_OUTBYTES];
|
|
+ size_t i;
|
|
+ bool success = true;
|
|
+
|
|
+ for (i = 0; i < BLAKE2S_KEYBYTES; ++i)
|
|
+ key[i] = (u8)i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(blake2s_testvecs); ++i)
|
|
+ buf[i] = (u8)i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(blake2s_keyed_testvecs); ++i) {
|
|
+ blake2s(hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES);
|
|
+ if (memcmp(hash, blake2s_keyed_testvecs[i], BLAKE2S_OUTBYTES)) {
|
|
+ pr_info("blake2s keyed self-test %zu: FAIL\n", i + 1);
|
|
+ success = false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(blake2s_testvecs); ++i) {
|
|
+ blake2s(hash, buf, NULL, BLAKE2S_OUTBYTES, i, 0);
|
|
+ if (memcmp(hash, blake2s_testvecs[i], BLAKE2S_OUTBYTES)) {
|
|
+ pr_info("blake2s unkeyed self-test %zu: FAIL\n", i + i);
|
|
+ success = false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (success)
|
|
+ pr_info("blake2s self-tests: pass\n");
|
|
+ return success;
|
|
+}
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/selftest/chacha20poly1305.h
|
|
@@ -0,0 +1,89 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifdef DEBUG
|
|
+/* ChaCha20-Poly1305 AEAD test vectors from RFC7539 2.8.2 */
|
|
+struct chacha20poly1305_testvec {
|
|
+ u8 *key, *nonce, *assoc, *input, *result;
|
|
+ size_t alen, ilen;
|
|
+};
|
|
+static const struct chacha20poly1305_testvec chacha20poly1305_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 = "\x01\x02\x03\x04\x05\x06\x07\x08",
|
|
+ .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 = "\x64\xa0\x86\x15\x75\x86\x1a\xf4\x60\xf0\x62\xc7\x9b\xe6\x43\xbd\x5e\x80\x5c\xfd\x34\x5c\xf3\x89\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2\x4c\x6c\xfc\x18\x75\x5d\x43\xee\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0\xbd\xb7\xb7\x3c\x32\x1b\x01\x00\xd4\xf0\x3b\x7f\x35\x58\x94\xcf\x33\x2f\x83\x0e\x71\x0b\x97\xce\x98\xc8\xa8\x4a\xbd\x0b\x94\x81\x14\xad\x17\x6e\x00\x8d\x33\xbd\x60\xf9\x82\xb1\xff\x37\xc8\x55\x97\x97\xa0\x6e\xf4\xf0\xef\x61\xc1\x86\x32\x4e\x2b\x35\x06\x38\x36\x06\x90\x7b\x6a\x7c\x02\xb0\xf9\xf6\x15\x7b\x53\xc8\x67\xe4\xb9\x16\x6c\x76\x7b\x80\x4d\x46\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9\x90\x40\xc5\xa4\x04\x33\x22\x5e\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e\xaf\x45\x34\xd7\xf8\x3f\xa1\x15\x5b\x00\x47\x71\x8c\xbc\x54\x6a\x0d\x07\x2b\x04\xb3\x56\x4e\xea\x1b\x42\x22\x73\xf5\x48\x27\x1a\x0b\xb2\x31\x60\x53\xfa\x76\x99\x19\x55\xeb\xd6\x31\x59\x43\x4e\xce\xbb\x4e\x46\x6d\xae\x5a\x10\x73\xa6\x72\x76\x27\x09\x7a\x10\x49\xe6\x17\xd9\x1d\x36\x10\x94\xfa\x68\xf0\xff\x77\x98\x71\x30\x30\x5b\xea\xba\x2e\xda\x04\xdf\x99\x7b\x71\x4d\x6c\x6f\x2c\x29\xa6\xad\x5c\xb4\x02\x2b\x02\x70\x9b\xee\xad\x9d\x67\x89\x0c\xbb\x22\x39\x23\x36\xfe\xa1\x85\x1f\x38"
|
|
+} };
|
|
+static const struct chacha20poly1305_testvec chacha20poly1305_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 = "\x01\x02\x03\x04\x05\x06\x07\x08",
|
|
+ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91",
|
|
+ .alen = 12,
|
|
+ .input = "\x64\xa0\x86\x15\x75\x86\x1a\xf4\x60\xf0\x62\xc7\x9b\xe6\x43\xbd\x5e\x80\x5c\xfd\x34\x5c\xf3\x89\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2\x4c\x6c\xfc\x18\x75\x5d\x43\xee\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0\xbd\xb7\xb7\x3c\x32\x1b\x01\x00\xd4\xf0\x3b\x7f\x35\x58\x94\xcf\x33\x2f\x83\x0e\x71\x0b\x97\xce\x98\xc8\xa8\x4a\xbd\x0b\x94\x81\x14\xad\x17\x6e\x00\x8d\x33\xbd\x60\xf9\x82\xb1\xff\x37\xc8\x55\x97\x97\xa0\x6e\xf4\xf0\xef\x61\xc1\x86\x32\x4e\x2b\x35\x06\x38\x36\x06\x90\x7b\x6a\x7c\x02\xb0\xf9\xf6\x15\x7b\x53\xc8\x67\xe4\xb9\x16\x6c\x76\x7b\x80\x4d\x46\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9\x90\x40\xc5\xa4\x04\x33\x22\x5e\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e\xaf\x45\x34\xd7\xf8\x3f\xa1\x15\x5b\x00\x47\x71\x8c\xbc\x54\x6a\x0d\x07\x2b\x04\xb3\x56\x4e\xea\x1b\x42\x22\x73\xf5\x48\x27\x1a\x0b\xb2\x31\x60\x53\xfa\x76\x99\x19\x55\xeb\xd6\x31\x59\x43\x4e\xce\xbb\x4e\x46\x6d\xae\x5a\x10\x73\xa6\x72\x76\x27\x09\x7a\x10\x49\xe6\x17\xd9\x1d\x36\x10\x94\xfa\x68\xf0\xff\x77\x98\x71\x30\x30\x5b\xea\xba\x2e\xda\x04\xdf\x99\x7b\x71\x4d\x6c\x6f\x2c\x29\xa6\xad\x5c\xb4\x02\x2b\x02\x70\x9b\xee\xad\x9d\x67\x89\x0c\xbb\x22\x39\x23\x36\xfe\xa1\x85\x1f\x38",
|
|
+ .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"
|
|
+} };
|
|
+
|
|
+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;
|
|
+ u8 computed_result[512];
|
|
+ bool success = true;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) {
|
|
+ memset(computed_result, 0, sizeof(computed_result));
|
|
+ success = chacha20poly1305_encrypt(computed_result, chacha20poly1305_enc_vectors[i].input, chacha20poly1305_enc_vectors[i].ilen, chacha20poly1305_enc_vectors[i].assoc, chacha20poly1305_enc_vectors[i].alen, le64_to_cpu(*(__force __le64 *)chacha20poly1305_enc_vectors[i].nonce), chacha20poly1305_enc_vectors[i].key);
|
|
+ if (memcmp(computed_result, chacha20poly1305_enc_vectors[i].result, chacha20poly1305_enc_vectors[i].ilen + POLY1305_MAC_SIZE)) {
|
|
+ pr_info("chacha20poly1305 encryption self-test %zu: FAIL\n", i + 1);
|
|
+ success = false;
|
|
+ }
|
|
+ }
|
|
+ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) {
|
|
+ memset(computed_result, 0, sizeof(computed_result));
|
|
+ success = chacha20poly1305_decrypt(computed_result, chacha20poly1305_dec_vectors[i].input, chacha20poly1305_dec_vectors[i].ilen, chacha20poly1305_dec_vectors[i].assoc, chacha20poly1305_dec_vectors[i].alen, le64_to_cpu(*(__force __le64 *)chacha20poly1305_dec_vectors[i].nonce), chacha20poly1305_dec_vectors[i].key);
|
|
+ if (!success || memcmp(computed_result, chacha20poly1305_dec_vectors[i].result, chacha20poly1305_dec_vectors[i].ilen - POLY1305_MAC_SIZE)) {
|
|
+ pr_info("chacha20poly1305 decryption self-test %zu: FAIL\n", i + 1);
|
|
+ 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;
|
|
+}
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/selftest/counter.h
|
|
@@ -0,0 +1,89 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifdef DEBUG
|
|
+bool packet_counter_selftest(void)
|
|
+{
|
|
+ bool success = true;
|
|
+ unsigned int test_num = 0, i;
|
|
+ union noise_counter counter;
|
|
+
|
|
+#define T_INIT do { memset(&counter, 0, sizeof(union noise_counter)); spin_lock_init(&counter.receive.lock); } while (0)
|
|
+#define T_LIM (COUNTER_WINDOW_SIZE + 1)
|
|
+#define T(n, v) do { ++test_num; if (counter_validate(&counter, n) != v) { pr_info("nonce counter self-test %u: FAIL\n", test_num); success = false; } } while (0)
|
|
+ T_INIT;
|
|
+ /* 1 */ T(0, true);
|
|
+ /* 2 */ T(1, true);
|
|
+ /* 3 */ T(1, false);
|
|
+ /* 4 */ T(9, true);
|
|
+ /* 5 */ T(8, true);
|
|
+ /* 6 */ T(7, true);
|
|
+ /* 7 */ T(7, false);
|
|
+ /* 8 */ T(T_LIM, true);
|
|
+ /* 9 */ T(T_LIM - 1, true);
|
|
+ /* 10 */ T(T_LIM - 1, false);
|
|
+ /* 11 */ T(T_LIM - 2, true);
|
|
+ /* 12 */ T(2, true);
|
|
+ /* 13 */ T(2, false);
|
|
+ /* 14 */ T(T_LIM + 16, true);
|
|
+ /* 15 */ T(3, false);
|
|
+ /* 16 */ T(T_LIM + 16, false);
|
|
+ /* 17 */ T(T_LIM * 4, true);
|
|
+ /* 18 */ T(T_LIM * 4 - (T_LIM - 1), true);
|
|
+ /* 19 */ T(10, false);
|
|
+ /* 20 */ T(T_LIM * 4 - T_LIM, false);
|
|
+ /* 21 */ T(T_LIM * 4 - (T_LIM + 1), false);
|
|
+ /* 22 */ T(T_LIM * 4 - (T_LIM - 2), true);
|
|
+ /* 23 */ T(T_LIM * 4 + 1 - T_LIM, false);
|
|
+ /* 24 */ T(0, false);
|
|
+ /* 25 */ T(REJECT_AFTER_MESSAGES, false);
|
|
+ /* 26 */ T(REJECT_AFTER_MESSAGES - 1, true);
|
|
+ /* 27 */ T(REJECT_AFTER_MESSAGES, false);
|
|
+ /* 28 */ T(REJECT_AFTER_MESSAGES - 1, false);
|
|
+ /* 29 */ T(REJECT_AFTER_MESSAGES - 2, true);
|
|
+ /* 30 */ T(REJECT_AFTER_MESSAGES + 1, false);
|
|
+ /* 31 */ T(REJECT_AFTER_MESSAGES + 2, false);
|
|
+ /* 32 */ T(REJECT_AFTER_MESSAGES - 2, false);
|
|
+ /* 33 */ T(REJECT_AFTER_MESSAGES - 3, true);
|
|
+ /* 34 */ T(0, false);
|
|
+
|
|
+ T_INIT;
|
|
+ for (i = 1; i <= COUNTER_WINDOW_SIZE; ++i)
|
|
+ T(i, true);
|
|
+ T(0, true);
|
|
+ T(0, false);
|
|
+
|
|
+ T_INIT;
|
|
+ for (i = 2; i <= COUNTER_WINDOW_SIZE + 1; ++i)
|
|
+ T(i, true);
|
|
+ T(1, true);
|
|
+ T(0, false);
|
|
+
|
|
+ T_INIT;
|
|
+ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 0 ;)
|
|
+ T(i, true);
|
|
+
|
|
+ T_INIT;
|
|
+ for (i = COUNTER_WINDOW_SIZE + 2; i-- > 1 ;)
|
|
+ T(i, true);
|
|
+ T(0, false);
|
|
+
|
|
+ T_INIT;
|
|
+ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1 ;)
|
|
+ T(i, true);
|
|
+ T(COUNTER_WINDOW_SIZE + 1, true);
|
|
+ T(0, false);
|
|
+
|
|
+ T_INIT;
|
|
+ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1 ;)
|
|
+ T(i, true);
|
|
+ T(0, true);
|
|
+ T(COUNTER_WINDOW_SIZE + 1, true);
|
|
+#undef T
|
|
+#undef T_LIM
|
|
+#undef T_INIT
|
|
+
|
|
+ if (success)
|
|
+ pr_info("nonce counter self-tests: pass\n");
|
|
+ return success;
|
|
+}
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/selftest/curve25519.h
|
|
@@ -0,0 +1,66 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifdef DEBUG
|
|
+struct curve25519_test_vector {
|
|
+ u8 private[CURVE25519_POINT_SIZE];
|
|
+ u8 public[CURVE25519_POINT_SIZE];
|
|
+ u8 result[CURVE25519_POINT_SIZE];
|
|
+};
|
|
+static const struct curve25519_test_vector curve25519_test_vectors[] = {
|
|
+ {
|
|
+ .private = { 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a },
|
|
+ .public = { 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f },
|
|
+ .result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 }
|
|
+ },
|
|
+ {
|
|
+ .private = { 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb },
|
|
+ .public = { 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a },
|
|
+ .result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 }
|
|
+ },
|
|
+ {
|
|
+ .private = { 1 },
|
|
+ .public = { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
+ .result = { 0x3c, 0x77, 0x77, 0xca, 0xf9, 0x97, 0xb2, 0x64, 0x41, 0x60, 0x77, 0x66, 0x5b, 0x4e, 0x22, 0x9d, 0xb, 0x95, 0x48, 0xdc, 0xc, 0xd8, 0x19, 0x98, 0xdd, 0xcd, 0xc5, 0xc8, 0x53, 0x3c, 0x79, 0x7f }
|
|
+ },
|
|
+ {
|
|
+ .private = { 1 },
|
|
+ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
|
+ .result = { 0xb3, 0x2d, 0x13, 0x62, 0xc2, 0x48, 0xd6, 0x2f, 0xe6, 0x26, 0x19, 0xcf, 0xf0, 0x4d, 0xd4, 0x3d, 0xb7, 0x3f, 0xfc, 0x1b, 0x63, 0x8, 0xed, 0xe3, 0xb, 0x78, 0xd8, 0x73, 0x80, 0xf1, 0xe8, 0x34 }
|
|
+ },
|
|
+ {
|
|
+ .private = { 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 },
|
|
+ .public = { 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c },
|
|
+ .result = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 }
|
|
+ },
|
|
+ {
|
|
+ .private = { 1, 2, 3, 4 },
|
|
+ .public = { 0 },
|
|
+ .result = { 0 }
|
|
+ },
|
|
+ {
|
|
+ .private = { 2, 4, 6, 8 },
|
|
+ .public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8 },
|
|
+ .result = { 0 }
|
|
+ }
|
|
+};
|
|
+bool curve25519_selftest(void)
|
|
+{
|
|
+ bool success = true;
|
|
+ size_t i = 0;
|
|
+ u8 out[CURVE25519_POINT_SIZE];
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(curve25519_test_vectors); ++i) {
|
|
+ memset(out, 0, CURVE25519_POINT_SIZE);
|
|
+ curve25519(out, curve25519_test_vectors[i].private, curve25519_test_vectors[i].public);
|
|
+ if (memcmp(out, curve25519_test_vectors[i].result, CURVE25519_POINT_SIZE)) {
|
|
+ pr_info("curve25519 self-test %zu: FAIL\n", i + 1);
|
|
+ success = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (success)
|
|
+ pr_info("curve25519 self-tests: pass\n");
|
|
+ return success;
|
|
+}
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/selftest/routing-table.h
|
|
@@ -0,0 +1,133 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifdef DEBUG
|
|
+static inline struct in_addr *ip4(u8 a, u8 b, u8 c, u8 d)
|
|
+{
|
|
+ static struct in_addr ip;
|
|
+ u8 *split = (u8 *)&ip;
|
|
+ split[0] = a;
|
|
+ split[1] = b;
|
|
+ split[2] = c;
|
|
+ split[3] = d;
|
|
+ return &ip;
|
|
+}
|
|
+static inline struct in6_addr *ip6(u32 a, u32 b, u32 c, u32 d)
|
|
+{
|
|
+ static struct in6_addr ip;
|
|
+ __be32 *split = (__be32 *)&ip;
|
|
+ split[0] = cpu_to_be32(a);
|
|
+ split[1] = cpu_to_be32(b);
|
|
+ split[2] = cpu_to_be32(c);
|
|
+ split[3] = cpu_to_be32(d);
|
|
+ return &ip;
|
|
+}
|
|
+
|
|
+bool routing_table_selftest(void)
|
|
+{
|
|
+ struct routing_table t;
|
|
+ struct wireguard_peer *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL, *g = NULL, *h = NULL;
|
|
+ size_t i = 0;
|
|
+ bool success = false;
|
|
+ struct in6_addr ip;
|
|
+ __be64 part;
|
|
+
|
|
+ routing_table_init(&t);
|
|
+#define init_peer(name) do { name = kzalloc(sizeof(struct wireguard_peer), GFP_KERNEL); if (!name) goto free; kref_init(&name->refcount); } while (0)
|
|
+ init_peer(a);
|
|
+ init_peer(b);
|
|
+ init_peer(c);
|
|
+ init_peer(d);
|
|
+ init_peer(e);
|
|
+ init_peer(f);
|
|
+ init_peer(g);
|
|
+ init_peer(h);
|
|
+#undef init_peer
|
|
+
|
|
+#define insert(version, mem, ipa, ipb, ipc, ipd, cidr) routing_table_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), cidr, mem)
|
|
+ insert(4, a, 192, 168, 4, 0, 24);
|
|
+ insert(4, b, 192, 168, 4, 4, 32);
|
|
+ insert(4, c, 192, 168, 0, 0, 16);
|
|
+ insert(4, d, 192, 95, 5, 64, 27);
|
|
+ insert(4, c, 192, 95, 5, 65, 27); /* replaces previous entry, and maskself is required */
|
|
+ insert(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
|
|
+ insert(6, c, 0x26075300, 0x60006b00, 0, 0, 64);
|
|
+ insert(4, e, 0, 0, 0, 0, 0);
|
|
+ insert(6, e, 0, 0, 0, 0, 0);
|
|
+ insert(6, f, 0, 0, 0, 0, 0); /* replaces previous entry */
|
|
+ insert(6, g, 0x24046800, 0, 0, 0, 32);
|
|
+ insert(6, h, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64); /* maskself is required */
|
|
+ insert(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128);
|
|
+ insert(4, g, 64, 15, 112, 0, 20);
|
|
+ insert(4, h, 64, 15, 123, 211, 25); /* maskself is required */
|
|
+ insert(4, a, 10, 0, 0, 0, 25);
|
|
+ insert(4, b, 10, 0, 0, 128, 25);
|
|
+ insert(4, a, 10, 1, 0, 0, 30);
|
|
+ insert(4, b, 10, 1, 0, 4, 30);
|
|
+ insert(4, c, 10, 1, 0, 8, 29);
|
|
+ insert(4, d, 10, 1, 0, 16, 29);
|
|
+#undef insert
|
|
+
|
|
+ success = true;
|
|
+#define test(version, mem, ipa, ipb, ipc, ipd) do { \
|
|
+ bool _s = routing_table_lookup_v##version(&t, ip##version(ipa, ipb, ipc, ipd)) == mem; \
|
|
+ ++i; \
|
|
+ if (!_s) { \
|
|
+ pr_info("routing table self-test %zu: FAIL\n", i); \
|
|
+ success = false; \
|
|
+ } \
|
|
+} while (0)
|
|
+ test(4, a, 192, 168, 4, 20);
|
|
+ test(4, a, 192, 168, 4, 0);
|
|
+ test(4, b, 192, 168, 4, 4);
|
|
+ test(4, c, 192, 168, 200, 182);
|
|
+ test(4, c, 192, 95, 5, 68);
|
|
+ test(4, e, 192, 95, 5, 96);
|
|
+ test(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543);
|
|
+ test(6, c, 0x26075300, 0x60006b00, 0, 0xc02e01ee);
|
|
+ test(6, f, 0x26075300, 0x60006b01, 0, 0);
|
|
+ test(6, g, 0x24046800, 0x40040806, 0, 0x1006);
|
|
+ test(6, g, 0x24046800, 0x40040806, 0x1234, 0x5678);
|
|
+ test(6, f, 0x240467ff, 0x40040806, 0x1234, 0x5678);
|
|
+ test(6, f, 0x24046801, 0x40040806, 0x1234, 0x5678);
|
|
+ test(6, h, 0x24046800, 0x40040800, 0x1234, 0x5678);
|
|
+ test(6, h, 0x24046800, 0x40040800, 0, 0);
|
|
+ test(6, h, 0x24046800, 0x40040800, 0x10101010, 0x10101010);
|
|
+ test(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef);
|
|
+ test(4, g, 64, 15, 116, 26);
|
|
+ test(4, g, 64, 15, 127, 3);
|
|
+ test(4, g, 64, 15, 123, 1);
|
|
+ test(4, h, 64, 15, 123, 128);
|
|
+ test(4, h, 64, 15, 123, 129);
|
|
+ test(4, a, 10, 0, 0, 52);
|
|
+ test(4, b, 10, 0, 0, 220);
|
|
+ test(4, a, 10, 1, 0, 2);
|
|
+ test(4, b, 10, 1, 0, 6);
|
|
+ test(4, c, 10, 1, 0, 10);
|
|
+ test(4, d, 10, 1, 0, 20);
|
|
+#undef test
|
|
+
|
|
+ /* These will hit the BUG_ON(len >= 128) in free_node if something goes wrong. */
|
|
+ for (i = 0; i < 128; ++i) {
|
|
+ part = cpu_to_be64(~(1LLU << (i % 64)));
|
|
+ memset(&ip, 0xff, 16);
|
|
+ memcpy((u8 *)&ip + (i < 64) * 8, &part, 8);
|
|
+ routing_table_insert_v6(&t, &ip, 128, a);
|
|
+ }
|
|
+
|
|
+ if (success)
|
|
+ pr_info("routing table self-tests: pass\n");
|
|
+
|
|
+free:
|
|
+ routing_table_free(&t);
|
|
+ kfree(a);
|
|
+ kfree(b);
|
|
+ kfree(c);
|
|
+ kfree(d);
|
|
+ kfree(e);
|
|
+ kfree(f);
|
|
+ kfree(g);
|
|
+ kfree(h);
|
|
+
|
|
+ return success;
|
|
+}
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/selftest/siphash.h
|
|
@@ -0,0 +1,89 @@
|
|
+/* Test cases for siphash.c
|
|
+ *
|
|
+ * Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ *
|
|
+ * SipHash: a fast short-input PRF
|
|
+ * https://131002.net/siphash/
|
|
+ *
|
|
+ * This implementation is specifically for SipHash2-4.
|
|
+ */
|
|
+
|
|
+#ifdef DEBUG
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/module.h>
|
|
+
|
|
+/* Test vectors taken from official reference source available at:
|
|
+ * https://131002.net/siphash/siphash24.c
|
|
+ */
|
|
+static const u64 test_vectors[64] = {
|
|
+ 0x726fdb47dd0e0e31ULL, 0x74f839c593dc67fdULL, 0x0d6c8009d9a94f5aULL,
|
|
+ 0x85676696d7fb7e2dULL, 0xcf2794e0277187b7ULL, 0x18765564cd99a68dULL,
|
|
+ 0xcbc9466e58fee3ceULL, 0xab0200f58b01d137ULL, 0x93f5f5799a932462ULL,
|
|
+ 0x9e0082df0ba9e4b0ULL, 0x7a5dbbc594ddb9f3ULL, 0xf4b32f46226bada7ULL,
|
|
+ 0x751e8fbc860ee5fbULL, 0x14ea5627c0843d90ULL, 0xf723ca908e7af2eeULL,
|
|
+ 0xa129ca6149be45e5ULL, 0x3f2acc7f57c29bdbULL, 0x699ae9f52cbe4794ULL,
|
|
+ 0x4bc1b3f0968dd39cULL, 0xbb6dc91da77961bdULL, 0xbed65cf21aa2ee98ULL,
|
|
+ 0xd0f2cbb02e3b67c7ULL, 0x93536795e3a33e88ULL, 0xa80c038ccd5ccec8ULL,
|
|
+ 0xb8ad50c6f649af94ULL, 0xbce192de8a85b8eaULL, 0x17d835b85bbb15f3ULL,
|
|
+ 0x2f2e6163076bcfadULL, 0xde4daaaca71dc9a5ULL, 0xa6a2506687956571ULL,
|
|
+ 0xad87a3535c49ef28ULL, 0x32d892fad841c342ULL, 0x7127512f72f27cceULL,
|
|
+ 0xa7f32346f95978e3ULL, 0x12e0b01abb051238ULL, 0x15e034d40fa197aeULL,
|
|
+ 0x314dffbe0815a3b4ULL, 0x027990f029623981ULL, 0xcadcd4e59ef40c4dULL,
|
|
+ 0x9abfd8766a33735cULL, 0x0e3ea96b5304a7d0ULL, 0xad0c42d6fc585992ULL,
|
|
+ 0x187306c89bc215a9ULL, 0xd4a60abcf3792b95ULL, 0xf935451de4f21df2ULL,
|
|
+ 0xa9538f0419755787ULL, 0xdb9acddff56ca510ULL, 0xd06c98cd5c0975ebULL,
|
|
+ 0xe612a3cb9ecba951ULL, 0xc766e62cfcadaf96ULL, 0xee64435a9752fe72ULL,
|
|
+ 0xa192d576b245165aULL, 0x0a8787bf8ecb74b2ULL, 0x81b3e73d20b49b6fULL,
|
|
+ 0x7fa8220ba3b2eceaULL, 0x245731c13ca42499ULL, 0xb78dbfaf3a8d83bdULL,
|
|
+ 0xea1ad565322a1a0bULL, 0x60e61c23a3795013ULL, 0x6606d7e446282b93ULL,
|
|
+ 0x6ca4ecb15c5f91e1ULL, 0x9f626da15c9625f3ULL, 0xe51b38608ef25f57ULL,
|
|
+ 0x958a324ceb064572ULL
|
|
+};
|
|
+static const siphash_key_t test_key =
|
|
+ { 0x0706050403020100ULL , 0x0f0e0d0c0b0a0908ULL };
|
|
+
|
|
+bool siphash_selftest(void)
|
|
+{
|
|
+ u8 in[64] __aligned(SIPHASH_ALIGNMENT);
|
|
+ u8 in_unaligned[65];
|
|
+ u8 i;
|
|
+ bool ret = true;
|
|
+
|
|
+ for (i = 0; i < 64; ++i) {
|
|
+ in[i] = i;
|
|
+ in_unaligned[i + 1] = i;
|
|
+ if (siphash(in, i, test_key) != test_vectors[i]) {
|
|
+ pr_info("siphash self-test aligned %u: FAIL\n", i + 1);
|
|
+ ret = false;
|
|
+ }
|
|
+ if (siphash(in_unaligned + 1, i, test_key) != test_vectors[i]) {
|
|
+ pr_info("siphash self-test unaligned %u: FAIL\n", i + 1);
|
|
+ ret = false;
|
|
+ }
|
|
+ }
|
|
+ if (siphash_1u64(0x0706050403020100ULL, test_key) != test_vectors[8]) {
|
|
+ pr_info("siphash self-test 1u64: FAIL\n");
|
|
+ ret = false;
|
|
+ }
|
|
+ if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, test_key) != test_vectors[16]) {
|
|
+ pr_info("siphash self-test 2u64: FAIL\n");
|
|
+ ret = false;
|
|
+ }
|
|
+ if (siphash_3u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
|
|
+ 0x1716151413121110ULL, test_key) != test_vectors[24]) {
|
|
+ pr_info("siphash self-test 3u64: FAIL\n");
|
|
+ ret = false;
|
|
+ }
|
|
+ if (siphash_4u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
|
|
+ 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL, test_key) != test_vectors[32]) {
|
|
+ pr_info("siphash self-test 4u64: FAIL\n");
|
|
+ ret = false;
|
|
+ }
|
|
+ if (ret)
|
|
+ pr_info("siphash self-tests: pass\n");
|
|
+ return ret;
|
|
+}
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/blake2s.c
|
|
@@ -0,0 +1,278 @@
|
|
+/* Original author: Samuel Neves <sneves@dei.uc.pt>
|
|
+ *
|
|
+ * Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ */
|
|
+
|
|
+#include "blake2s.h"
|
|
+
|
|
+#include <linux/types.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/kernel.h>
|
|
+
|
|
+typedef struct {
|
|
+ u8 digest_length;
|
|
+ u8 key_length;
|
|
+ u8 fanout;
|
|
+ u8 depth;
|
|
+ u32 leaf_length;
|
|
+ u8 node_offset[6];
|
|
+ u8 node_depth;
|
|
+ u8 inner_length;
|
|
+ u8 salt[8];
|
|
+ u8 personal[8];
|
|
+} __packed blake2s_param;
|
|
+
|
|
+static const u32 blake2s_iv[8] = {
|
|
+ 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
|
|
+ 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
|
|
+};
|
|
+
|
|
+static const u8 blake2s_sigma[10][16] = {
|
|
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
|
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
|
+ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
|
+ {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
|
+ {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
|
+ {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
|
+ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
|
+ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
|
+ {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
|
+ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
|
|
+};
|
|
+
|
|
+static inline u32 le32_to_cpuvp(const void *p)
|
|
+{
|
|
+ return le32_to_cpup(p);
|
|
+}
|
|
+
|
|
+static inline void blake2s_set_lastblock(struct blake2s_state *state)
|
|
+{
|
|
+ if (state->last_node)
|
|
+ state->f[1] = -1;
|
|
+ state->f[0] = -1;
|
|
+}
|
|
+
|
|
+static inline void blake2s_increment_counter(struct blake2s_state *state, const u32 inc)
|
|
+{
|
|
+ state->t[0] += inc;
|
|
+ state->t[1] += (state->t[0] < inc);
|
|
+}
|
|
+
|
|
+static inline void blake2s_init_param(struct blake2s_state *state, const blake2s_param *param)
|
|
+{
|
|
+ const u32 *p;
|
|
+ int i;
|
|
+ memset(state, 0, sizeof(struct blake2s_state));
|
|
+ for (i = 0; i < 8; ++i)
|
|
+ state->h[i] = blake2s_iv[i];
|
|
+ p = (const u32 *)param;
|
|
+ /* IV XOR ParamBlock */
|
|
+ for (i = 0; i < 8; ++i)
|
|
+ state->h[i] ^= le32_to_cpuvp(&p[i]);
|
|
+}
|
|
+
|
|
+void blake2s_init(struct blake2s_state *state, const u8 outlen)
|
|
+{
|
|
+ blake2s_param param = {
|
|
+ .digest_length = outlen,
|
|
+ .fanout = 1,
|
|
+ .depth = 1
|
|
+ };
|
|
+
|
|
+#ifdef DEBUG
|
|
+ BUG_ON(!outlen || outlen > BLAKE2S_OUTBYTES);
|
|
+#endif
|
|
+ blake2s_init_param(state, ¶m);
|
|
+}
|
|
+
|
|
+void blake2s_init_key(struct blake2s_state *state, const u8 outlen, const void *key, const u8 keylen)
|
|
+{
|
|
+ blake2s_param param = {
|
|
+ .digest_length = outlen,
|
|
+ .key_length = keylen,
|
|
+ .fanout = 1,
|
|
+ .depth = 1
|
|
+ };
|
|
+ u8 block[BLAKE2S_BLOCKBYTES] = { 0 };
|
|
+
|
|
+#ifdef DEBUG
|
|
+ BUG_ON(!outlen || outlen > BLAKE2S_OUTBYTES || !key || !keylen || keylen > BLAKE2S_KEYBYTES);
|
|
+#endif
|
|
+ blake2s_init_param(state, ¶m);
|
|
+ memcpy(block, key, keylen);
|
|
+ blake2s_update(state, block, BLAKE2S_BLOCKBYTES);
|
|
+ memzero_explicit(block, BLAKE2S_BLOCKBYTES);
|
|
+}
|
|
+
|
|
+static inline void blake2s_compress(struct blake2s_state *state, const u8 block[BLAKE2S_BLOCKBYTES])
|
|
+{
|
|
+ u32 m[16];
|
|
+ u32 v[16];
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < 16; ++i)
|
|
+ m[i] = le32_to_cpuvp(block + i * sizeof(m[i]));
|
|
+
|
|
+ for (i = 0; i < 8; ++i)
|
|
+ v[i] = state->h[i];
|
|
+
|
|
+ v[8] = blake2s_iv[0];
|
|
+ v[9] = blake2s_iv[1];
|
|
+ v[10] = blake2s_iv[2];
|
|
+ v[11] = blake2s_iv[3];
|
|
+ v[12] = state->t[0] ^ blake2s_iv[4];
|
|
+ v[13] = state->t[1] ^ blake2s_iv[5];
|
|
+ v[14] = state->f[0] ^ blake2s_iv[6];
|
|
+ v[15] = state->f[1] ^ blake2s_iv[7];
|
|
+#define G(r,i,a,b,c,d) \
|
|
+ do { \
|
|
+ a += b + m[blake2s_sigma[r][2 * i + 0]]; \
|
|
+ d = ror32(d ^ a, 16); \
|
|
+ c += d; \
|
|
+ b = ror32(b ^ c, 12); \
|
|
+ a += b + m[blake2s_sigma[r][2 * i + 1]]; \
|
|
+ d = ror32(d ^ a, 8); \
|
|
+ c += d; \
|
|
+ b = ror32(b ^ c, 7); \
|
|
+ } while(0)
|
|
+#define ROUND(r) \
|
|
+ do { \
|
|
+ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
|
|
+ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
|
|
+ G(r,2,v[ 2],v[ 6],v[10],v[14]); \
|
|
+ G(r,3,v[ 3],v[ 7],v[11],v[15]); \
|
|
+ G(r,4,v[ 0],v[ 5],v[10],v[15]); \
|
|
+ G(r,5,v[ 1],v[ 6],v[11],v[12]); \
|
|
+ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
|
|
+ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
|
|
+} while(0)
|
|
+ ROUND(0);
|
|
+ ROUND(1);
|
|
+ ROUND(2);
|
|
+ ROUND(3);
|
|
+ ROUND(4);
|
|
+ ROUND(5);
|
|
+ ROUND(6);
|
|
+ ROUND(7);
|
|
+ ROUND(8);
|
|
+ ROUND(9);
|
|
+
|
|
+ for (i = 0; i < 8; ++i)
|
|
+ state->h[i] = state->h[i] ^ v[i] ^ v[i + 8];
|
|
+#undef G
|
|
+#undef ROUND
|
|
+}
|
|
+
|
|
+void blake2s_update(struct blake2s_state *state, const u8 *in, u64 inlen)
|
|
+{
|
|
+ size_t left, fill;
|
|
+ while (inlen > 0) {
|
|
+ left = state->buflen;
|
|
+ fill = 2 * BLAKE2S_BLOCKBYTES - left;
|
|
+
|
|
+ if (inlen > fill) {
|
|
+ memcpy(state->buf + left, in, fill); // Fill buffer
|
|
+ state->buflen += fill;
|
|
+ blake2s_increment_counter(state, BLAKE2S_BLOCKBYTES);
|
|
+ blake2s_compress(state, state->buf); // Compress
|
|
+ memcpy(state->buf, state->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES);// Shift buffer left
|
|
+ state->buflen -= BLAKE2S_BLOCKBYTES;
|
|
+ in += fill;
|
|
+ inlen -= fill;
|
|
+ } else { // inlen <= fill
|
|
+ memcpy(state->buf + left, in, inlen);
|
|
+ state->buflen += inlen; // Be lazy, do not compress
|
|
+ in += inlen;
|
|
+ inlen -= inlen;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void blake2s_final(struct blake2s_state *state, u8 *out, u8 outlen)
|
|
+{
|
|
+ u8 buffer[BLAKE2S_OUTBYTES] = { 0 };
|
|
+ int i;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ BUG_ON(!out || !outlen || outlen > BLAKE2S_OUTBYTES);
|
|
+#endif
|
|
+
|
|
+ if (state->buflen > BLAKE2S_BLOCKBYTES) {
|
|
+ blake2s_increment_counter(state, BLAKE2S_BLOCKBYTES);
|
|
+ blake2s_compress(state, state->buf);
|
|
+ state->buflen -= BLAKE2S_BLOCKBYTES;
|
|
+ memcpy(state->buf, state->buf + BLAKE2S_BLOCKBYTES, state->buflen);
|
|
+ }
|
|
+
|
|
+ blake2s_increment_counter(state, (u32) state->buflen);
|
|
+ blake2s_set_lastblock(state);
|
|
+ memset(state->buf + state->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - state->buflen); /* Padding */
|
|
+ blake2s_compress(state, state->buf);
|
|
+
|
|
+ for (i = 0; i < 8; ++i) /* output full hash to temp buffer */
|
|
+ *(__le32 *)(buffer + sizeof(state->h[i]) * i) = cpu_to_le32(state->h[i]);
|
|
+
|
|
+ memcpy(out, buffer, outlen);
|
|
+
|
|
+ /* Burn state from stack */
|
|
+ memzero_explicit(buffer, BLAKE2S_OUTBYTES);
|
|
+ memzero_explicit(state, sizeof(struct blake2s_state));
|
|
+}
|
|
+
|
|
+void blake2s(u8 *out, const u8 *in, const u8 *key, const u8 outlen, u64 inlen, const u8 keylen)
|
|
+{
|
|
+ struct blake2s_state state;
|
|
+
|
|
+#ifdef DEBUG
|
|
+ BUG_ON((!in && inlen > 0) || !out || !outlen || outlen > BLAKE2S_OUTBYTES || keylen > BLAKE2S_KEYBYTES);
|
|
+#endif
|
|
+
|
|
+ if (keylen > 0 && key)
|
|
+ blake2s_init_key(&state, outlen, key, keylen);
|
|
+ else
|
|
+ blake2s_init(&state, outlen);
|
|
+
|
|
+ blake2s_update(&state, in, inlen);
|
|
+ blake2s_final(&state, out, outlen);
|
|
+}
|
|
+
|
|
+void blake2s_hmac(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u64 keylen)
|
|
+{
|
|
+ struct blake2s_state state;
|
|
+ u8 o_key[BLAKE2S_BLOCKBYTES] = { 0 };
|
|
+ u8 i_key[BLAKE2S_BLOCKBYTES] = { 0 };
|
|
+ u8 i_hash[BLAKE2S_OUTBYTES];
|
|
+ int i;
|
|
+
|
|
+ if (keylen > BLAKE2S_BLOCKBYTES) {
|
|
+ blake2s_init(&state, BLAKE2S_OUTBYTES);
|
|
+ blake2s_update(&state, key, keylen);
|
|
+ blake2s_final(&state, o_key, BLAKE2S_OUTBYTES);
|
|
+ memcpy(i_key, o_key, BLAKE2S_OUTBYTES);
|
|
+ } else {
|
|
+ memcpy(o_key, key, keylen);
|
|
+ memcpy(i_key, key, keylen);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < BLAKE2S_BLOCKBYTES; ++i) {
|
|
+ o_key[i] ^= 0x5c;
|
|
+ i_key[i] ^= 0x36;
|
|
+ }
|
|
+
|
|
+ blake2s_init(&state, BLAKE2S_OUTBYTES);
|
|
+ blake2s_update(&state, i_key, BLAKE2S_BLOCKBYTES);
|
|
+ blake2s_update(&state, in, inlen);
|
|
+ blake2s_final(&state, i_hash, BLAKE2S_OUTBYTES);
|
|
+
|
|
+ blake2s_init(&state, BLAKE2S_OUTBYTES);
|
|
+ blake2s_update(&state, o_key, BLAKE2S_BLOCKBYTES);
|
|
+ blake2s_update(&state, i_hash, BLAKE2S_OUTBYTES);
|
|
+ blake2s_final(&state, i_hash, BLAKE2S_OUTBYTES);
|
|
+
|
|
+ memcpy(out, i_hash, outlen);
|
|
+ memzero_explicit(o_key, BLAKE2S_BLOCKBYTES);
|
|
+ memzero_explicit(i_key, BLAKE2S_BLOCKBYTES);
|
|
+ memzero_explicit(i_hash, BLAKE2S_OUTBYTES);
|
|
+}
|
|
+
|
|
+#include "../selftest/blake2s.h"
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/chacha20poly1305.c
|
|
@@ -0,0 +1,811 @@
|
|
+/*
|
|
+ * Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ * Copyright 2015 Martin Willi.
|
|
+ */
|
|
+
|
|
+#include "chacha20poly1305.h"
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/version.h>
|
|
+#include <crypto/algapi.h>
|
|
+#include <crypto/scatterwalk.h>
|
|
+#include <asm/unaligned.h>
|
|
+
|
|
+#ifdef CONFIG_X86_64
|
|
+#include <asm/cpufeature.h>
|
|
+#include <asm/processor.h>
|
|
+#ifdef CONFIG_AS_SSSE3
|
|
+asmlinkage void chacha20_asm_block_xor_ssse3(u32 *state, u8 *dst, const u8 *src);
|
|
+asmlinkage void chacha20_asm_4block_xor_ssse3(u32 *state, u8 *dst, const u8 *src);
|
|
+#endif
|
|
+#ifdef CONFIG_AS_AVX2
|
|
+asmlinkage void chacha20_asm_8block_xor_avx2(u32 *state, u8 *dst, const u8 *src);
|
|
+#endif
|
|
+asmlinkage void poly1305_asm_block_sse2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks);
|
|
+asmlinkage void poly1305_asm_2block_sse2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks, const u32 *u);
|
|
+#ifdef CONFIG_AS_AVX2
|
|
+asmlinkage void poly1305_asm_4block_avx2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks, const u32 *u);
|
|
+#endif
|
|
+static bool chacha20poly1305_use_avx2 __read_mostly = false;
|
|
+static bool chacha20poly1305_use_ssse3 __read_mostly = false;
|
|
+static bool chacha20poly1305_use_sse2 __read_mostly = false;
|
|
+void chacha20poly1305_init(void)
|
|
+{
|
|
+ chacha20poly1305_use_sse2 = boot_cpu_has(X86_FEATURE_XMM2);
|
|
+ chacha20poly1305_use_ssse3 = boot_cpu_has(X86_FEATURE_SSSE3);
|
|
+ chacha20poly1305_use_avx2 = boot_cpu_has(X86_FEATURE_AVX) && boot_cpu_has(X86_FEATURE_AVX2);
|
|
+}
|
|
+#else
|
|
+void chacha20poly1305_init(void) { }
|
|
+#endif
|
|
+
|
|
+#define CHACHA20_IV_SIZE 16
|
|
+#define CHACHA20_KEY_SIZE 32
|
|
+#define CHACHA20_BLOCK_SIZE 64
|
|
+#define POLY1305_BLOCK_SIZE 16
|
|
+#define POLY1305_KEY_SIZE 32
|
|
+#define POLY1305_MAC_SIZE 16
|
|
+
|
|
+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));
|
|
+}
|
|
+
|
|
+static inline u64 mlt(u64 a, u64 b)
|
|
+{
|
|
+ return a * b;
|
|
+}
|
|
+
|
|
+static inline u32 sr(u64 v, u_char n)
|
|
+{
|
|
+ return v >> n;
|
|
+}
|
|
+
|
|
+static inline u32 and(u32 v, u32 mask)
|
|
+{
|
|
+ return v & mask;
|
|
+}
|
|
+
|
|
+struct chacha20_ctx {
|
|
+ u32 state[CHACHA20_BLOCK_SIZE / sizeof(u32)];
|
|
+} __aligned(32);
|
|
+
|
|
+static void chacha20_generic_block(struct chacha20_ctx *ctx, void *stream)
|
|
+{
|
|
+ u32 x[CHACHA20_BLOCK_SIZE / sizeof(u32)];
|
|
+ __le32 *out = stream;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(x); i++)
|
|
+ x[i] = ctx->state[i];
|
|
+
|
|
+ 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);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(x); i++)
|
|
+ out[i] = cpu_to_le32(x[i] + ctx->state[i]);
|
|
+
|
|
+ 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)])
|
|
+{
|
|
+ ctx->state[0] = le32_to_cpuvp(constant + 0);
|
|
+ ctx->state[1] = le32_to_cpuvp(constant + 4);
|
|
+ ctx->state[2] = le32_to_cpuvp(constant + 8);
|
|
+ ctx->state[3] = le32_to_cpuvp(constant + 12);
|
|
+ ctx->state[4] = le32_to_cpuvp(key + 0);
|
|
+ ctx->state[5] = le32_to_cpuvp(key + 4);
|
|
+ ctx->state[6] = le32_to_cpuvp(key + 8);
|
|
+ ctx->state[7] = le32_to_cpuvp(key + 12);
|
|
+ ctx->state[8] = le32_to_cpuvp(key + 16);
|
|
+ ctx->state[9] = le32_to_cpuvp(key + 20);
|
|
+ ctx->state[10] = le32_to_cpuvp(key + 24);
|
|
+ ctx->state[11] = le32_to_cpuvp(key + 28);
|
|
+ ctx->state[12] = 0;
|
|
+ ctx->state[13] = 0;
|
|
+ ctx->state[14] = le32_to_cpuvp(nonce + 0);
|
|
+ ctx->state[15] = le32_to_cpuvp(nonce + 4);
|
|
+}
|
|
+
|
|
+static void chacha20_crypt(struct chacha20_ctx *ctx, u8 *dst, const u8 *src, unsigned int bytes, bool have_simd)
|
|
+{
|
|
+ u8 buf[CHACHA20_BLOCK_SIZE];
|
|
+
|
|
+ if (!have_simd
|
|
+#ifdef CONFIG_X86_64
|
|
+ || !chacha20poly1305_use_ssse3
|
|
+#endif
|
|
+ )
|
|
+ goto no_simd;
|
|
+
|
|
+#ifdef CONFIG_X86_64
|
|
+#ifdef CONFIG_AS_AVX2
|
|
+ if (chacha20poly1305_use_avx2) {
|
|
+ while (bytes >= CHACHA20_BLOCK_SIZE * 8) {
|
|
+ chacha20_asm_8block_xor_avx2(ctx->state, dst, src);
|
|
+ bytes -= CHACHA20_BLOCK_SIZE * 8;
|
|
+ src += CHACHA20_BLOCK_SIZE * 8;
|
|
+ dst += CHACHA20_BLOCK_SIZE * 8;
|
|
+ ctx->state[12] += 8;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+#ifdef CONFIG_AS_SSSE3
|
|
+ while (bytes >= CHACHA20_BLOCK_SIZE * 4) {
|
|
+ chacha20_asm_4block_xor_ssse3(ctx->state, dst, src);
|
|
+ bytes -= CHACHA20_BLOCK_SIZE * 4;
|
|
+ src += CHACHA20_BLOCK_SIZE * 4;
|
|
+ dst += CHACHA20_BLOCK_SIZE * 4;
|
|
+ ctx->state[12] += 4;
|
|
+ }
|
|
+ while (bytes >= CHACHA20_BLOCK_SIZE) {
|
|
+ chacha20_asm_block_xor_ssse3(ctx->state, dst, src);
|
|
+ bytes -= CHACHA20_BLOCK_SIZE;
|
|
+ src += CHACHA20_BLOCK_SIZE;
|
|
+ dst += CHACHA20_BLOCK_SIZE;
|
|
+ ctx->state[12]++;
|
|
+ }
|
|
+ if (bytes) {
|
|
+ memcpy(buf, src, bytes);
|
|
+ chacha20_asm_block_xor_ssse3(ctx->state, buf, buf);
|
|
+ memcpy(dst, buf, bytes);
|
|
+ }
|
|
+ return;
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+no_simd:
|
|
+ if (dst != src)
|
|
+ memcpy(dst, src, bytes);
|
|
+
|
|
+ while (bytes >= CHACHA20_BLOCK_SIZE) {
|
|
+ chacha20_generic_block(ctx, buf);
|
|
+ crypto_xor(dst, buf, CHACHA20_BLOCK_SIZE);
|
|
+ bytes -= CHACHA20_BLOCK_SIZE;
|
|
+ dst += CHACHA20_BLOCK_SIZE;
|
|
+ }
|
|
+ if (bytes) {
|
|
+ chacha20_generic_block(ctx, buf);
|
|
+ crypto_xor(dst, buf, bytes);
|
|
+ }
|
|
+}
|
|
+
|
|
+struct poly1305_ctx {
|
|
+ /* key */
|
|
+ u32 r[5];
|
|
+ /* finalize key */
|
|
+ u32 s[4];
|
|
+ /* accumulator */
|
|
+ u32 h[5];
|
|
+ /* partial buffer */
|
|
+ u8 buf[POLY1305_BLOCK_SIZE];
|
|
+ /* bytes used in partial buffer */
|
|
+ unsigned int buflen;
|
|
+ /* derived key u set? */
|
|
+ bool uset;
|
|
+ /* derived keys r^3, r^4 set? */
|
|
+ bool wset;
|
|
+ /* derived Poly1305 key r^2 */
|
|
+ u32 u[5];
|
|
+ /* derived Poly1305 key r^3 */
|
|
+ u32 r3[5];
|
|
+ /* derived Poly1305 key r^4 */
|
|
+ u32 r4[5];
|
|
+};
|
|
+
|
|
+static void poly1305_init(struct poly1305_ctx *ctx, const u8 key[POLY1305_KEY_SIZE])
|
|
+{
|
|
+ memset(ctx, 0, sizeof(struct poly1305_ctx));
|
|
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
|
+ ctx->r[0] = (le32_to_cpuvp(key + 0) >> 0) & 0x3ffffff;
|
|
+ ctx->r[1] = (get_unaligned_le32(key + 3) >> 2) & 0x3ffff03;
|
|
+ ctx->r[2] = (get_unaligned_le32(key + 6) >> 4) & 0x3ffc0ff;
|
|
+ ctx->r[3] = (get_unaligned_le32(key + 9) >> 6) & 0x3f03fff;
|
|
+ ctx->r[4] = (le32_to_cpuvp(key + 12) >> 8) & 0x00fffff;
|
|
+ ctx->s[0] = le32_to_cpuvp(key + 16);
|
|
+ ctx->s[1] = le32_to_cpuvp(key + 20);
|
|
+ ctx->s[2] = le32_to_cpuvp(key + 24);
|
|
+ ctx->s[3] = le32_to_cpuvp(key + 28);
|
|
+}
|
|
+
|
|
+static unsigned int poly1305_generic_blocks(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen, u32 hibit)
|
|
+{
|
|
+ u32 r0, r1, r2, r3, r4;
|
|
+ u32 s1, s2, s3, s4;
|
|
+ u32 h0, h1, h2, h3, h4;
|
|
+ u64 d0, d1, d2, d3, d4;
|
|
+
|
|
+ r0 = ctx->r[0];
|
|
+ r1 = ctx->r[1];
|
|
+ r2 = ctx->r[2];
|
|
+ r3 = ctx->r[3];
|
|
+ r4 = ctx->r[4];
|
|
+
|
|
+ s1 = r1 * 5;
|
|
+ s2 = r2 * 5;
|
|
+ s3 = r3 * 5;
|
|
+ s4 = r4 * 5;
|
|
+
|
|
+ h0 = ctx->h[0];
|
|
+ h1 = ctx->h[1];
|
|
+ h2 = ctx->h[2];
|
|
+ h3 = ctx->h[3];
|
|
+ h4 = ctx->h[4];
|
|
+
|
|
+ while (likely(srclen >= POLY1305_BLOCK_SIZE)) {
|
|
+ /* h += m[i] */
|
|
+ h0 += (le32_to_cpuvp(src + 0) >> 0) & 0x3ffffff;
|
|
+ h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff;
|
|
+ h2 += (get_unaligned_le32(src + 6) >> 4) & 0x3ffffff;
|
|
+ h3 += (get_unaligned_le32(src + 9) >> 6) & 0x3ffffff;
|
|
+ h4 += (le32_to_cpuvp(src + 12) >> 8) | hibit;
|
|
+
|
|
+ /* h *= r */
|
|
+ d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + mlt(h3, s2) + mlt(h4, s1);
|
|
+ d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + mlt(h3, s3) + mlt(h4, s2);
|
|
+ d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + mlt(h3, s4) + mlt(h4, s3);
|
|
+ d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + mlt(h3, r0) + mlt(h4, s4);
|
|
+ d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + mlt(h3, r1) + mlt(h4, r0);
|
|
+
|
|
+ /* (partial) h %= p */
|
|
+ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff);
|
|
+ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff);
|
|
+ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff);
|
|
+ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff);
|
|
+ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
|
|
+ h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
|
|
+
|
|
+ src += POLY1305_BLOCK_SIZE;
|
|
+ srclen -= POLY1305_BLOCK_SIZE;
|
|
+ }
|
|
+
|
|
+ ctx->h[0] = h0;
|
|
+ ctx->h[1] = h1;
|
|
+ ctx->h[2] = h2;
|
|
+ ctx->h[3] = h3;
|
|
+ ctx->h[4] = h4;
|
|
+
|
|
+ return srclen;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_X86_64
|
|
+static void poly1305_simd_mult(u32 *a, const u32 *b)
|
|
+{
|
|
+ u8 m[POLY1305_BLOCK_SIZE];
|
|
+
|
|
+ memset(m, 0, sizeof(m));
|
|
+ /* The poly1305 block function adds a hi-bit to the accumulator which
|
|
+ * we don't need for key multiplication; compensate for it. */
|
|
+ a[4] -= 1 << 24;
|
|
+ poly1305_asm_block_sse2(a, m, b, 1);
|
|
+}
|
|
+
|
|
+static unsigned int poly1305_simd_blocks(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen)
|
|
+{
|
|
+ unsigned int blocks;
|
|
+
|
|
+#ifdef CONFIG_AS_AVX2
|
|
+ if (chacha20poly1305_use_avx2 && srclen >= POLY1305_BLOCK_SIZE * 4) {
|
|
+ if (unlikely(!ctx->wset)) {
|
|
+ if (!ctx->uset) {
|
|
+ memcpy(ctx->u, ctx->r, sizeof(ctx->u));
|
|
+ poly1305_simd_mult(ctx->u, ctx->r);
|
|
+ ctx->uset = true;
|
|
+ }
|
|
+ memcpy(ctx->r3, ctx->u, sizeof(ctx->u));
|
|
+ poly1305_simd_mult(ctx->r3, ctx->r);
|
|
+ memcpy(ctx->r4, ctx->r3, sizeof(ctx->u));
|
|
+ poly1305_simd_mult(ctx->r4, ctx->r);
|
|
+ ctx->wset = true;
|
|
+ }
|
|
+ blocks = srclen / (POLY1305_BLOCK_SIZE * 4);
|
|
+ poly1305_asm_4block_avx2(ctx->h, src, ctx->r, blocks, ctx->u);
|
|
+ src += POLY1305_BLOCK_SIZE * 4 * blocks;
|
|
+ srclen -= POLY1305_BLOCK_SIZE * 4 * blocks;
|
|
+ }
|
|
+#endif
|
|
+ if (likely(srclen >= POLY1305_BLOCK_SIZE * 2)) {
|
|
+ if (unlikely(!ctx->uset)) {
|
|
+ memcpy(ctx->u, ctx->r, sizeof(ctx->u));
|
|
+ poly1305_simd_mult(ctx->u, ctx->r);
|
|
+ ctx->uset = true;
|
|
+ }
|
|
+ blocks = srclen / (POLY1305_BLOCK_SIZE * 2);
|
|
+ poly1305_asm_2block_sse2(ctx->h, src, ctx->r, blocks, ctx->u);
|
|
+ src += POLY1305_BLOCK_SIZE * 2 * blocks;
|
|
+ srclen -= POLY1305_BLOCK_SIZE * 2 * blocks;
|
|
+ }
|
|
+ if (srclen >= POLY1305_BLOCK_SIZE) {
|
|
+ poly1305_asm_block_sse2(ctx->h, src, ctx->r, 1);
|
|
+ srclen -= POLY1305_BLOCK_SIZE;
|
|
+ }
|
|
+ return srclen;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void poly1305_update(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen, bool have_simd)
|
|
+{
|
|
+ unsigned int bytes;
|
|
+
|
|
+ if (unlikely(ctx->buflen)) {
|
|
+ bytes = min(srclen, POLY1305_BLOCK_SIZE - ctx->buflen);
|
|
+ memcpy(ctx->buf + ctx->buflen, src, bytes);
|
|
+ src += bytes;
|
|
+ srclen -= bytes;
|
|
+ ctx->buflen += bytes;
|
|
+
|
|
+ if (ctx->buflen == POLY1305_BLOCK_SIZE) {
|
|
+#ifdef CONFIG_X86_64
|
|
+
|
|
+ if (have_simd && chacha20poly1305_use_sse2)
|
|
+ poly1305_simd_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE);
|
|
+ else
|
|
+#endif
|
|
+ poly1305_generic_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE, 1 << 24);
|
|
+ ctx->buflen = 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
|
|
+#ifdef CONFIG_X86_64
|
|
+
|
|
+ if (have_simd && chacha20poly1305_use_sse2)
|
|
+ bytes = poly1305_simd_blocks(ctx, src, srclen);
|
|
+ else
|
|
+#endif
|
|
+ bytes = poly1305_generic_blocks(ctx, src, srclen, 1 << 24);
|
|
+ src += srclen - bytes;
|
|
+ srclen = bytes;
|
|
+ }
|
|
+
|
|
+ if (unlikely(srclen)) {
|
|
+ ctx->buflen = srclen;
|
|
+ memcpy(ctx->buf, src, srclen);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void poly1305_finish(struct poly1305_ctx *ctx, u8 *dst)
|
|
+{
|
|
+ __le32 *mac = (__le32 *)dst;
|
|
+ u32 h0, h1, h2, h3, h4;
|
|
+ u32 g0, g1, g2, g3, g4;
|
|
+ u32 mask;
|
|
+ u64 f = 0;
|
|
+
|
|
+ if (unlikely(ctx->buflen)) {
|
|
+ ctx->buf[ctx->buflen++] = 1;
|
|
+ memset(ctx->buf + ctx->buflen, 0, POLY1305_BLOCK_SIZE - ctx->buflen);
|
|
+ poly1305_generic_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE, 0);
|
|
+ }
|
|
+
|
|
+ /* fully carry h */
|
|
+ h0 = ctx->h[0];
|
|
+ h1 = ctx->h[1];
|
|
+ h2 = ctx->h[2];
|
|
+ h3 = ctx->h[3];
|
|
+ h4 = ctx->h[4];
|
|
+
|
|
+ h2 += (h1 >> 26); h1 = h1 & 0x3ffffff;
|
|
+ h3 += (h2 >> 26); h2 = h2 & 0x3ffffff;
|
|
+ h4 += (h3 >> 26); h3 = h3 & 0x3ffffff;
|
|
+ h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
|
|
+ h1 += (h0 >> 26); h0 = h0 & 0x3ffffff;
|
|
+
|
|
+ /* compute h + -p */
|
|
+ g0 = h0 + 5;
|
|
+ g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff;
|
|
+ g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff;
|
|
+ g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff;
|
|
+ g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
|
|
+
|
|
+ /* select h if h < p, or h + -p if h >= p */
|
|
+ mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
|
|
+ g0 &= mask;
|
|
+ g1 &= mask;
|
|
+ g2 &= mask;
|
|
+ g3 &= mask;
|
|
+ g4 &= mask;
|
|
+ mask = ~mask;
|
|
+ h0 = (h0 & mask) | g0;
|
|
+ h1 = (h1 & mask) | g1;
|
|
+ h2 = (h2 & mask) | g2;
|
|
+ h3 = (h3 & mask) | g3;
|
|
+ h4 = (h4 & mask) | g4;
|
|
+
|
|
+ /* h = h % (2^128) */
|
|
+ h0 = (h0 >> 0) | (h1 << 26);
|
|
+ h1 = (h1 >> 6) | (h2 << 20);
|
|
+ h2 = (h2 >> 12) | (h3 << 14);
|
|
+ h3 = (h3 >> 18) | (h4 << 8);
|
|
+
|
|
+ /* mac = (h + s) % (2^128) */
|
|
+ f = (f >> 32) + h0 + ctx->s[0]; mac[0] = cpu_to_le32(f);
|
|
+ f = (f >> 32) + h1 + ctx->s[1]; mac[1] = cpu_to_le32(f);
|
|
+ f = (f >> 32) + h2 + ctx->s[2]; mac[2] = cpu_to_le32(f);
|
|
+ f = (f >> 32) + h3 + ctx->s[3]; mac[3] = cpu_to_le32(f);
|
|
+}
|
|
+
|
|
+static const u8 pad0[16] = { 0 };
|
|
+
|
|
+static struct crypto_alg chacha20_alg = {
|
|
+ .cra_blocksize = 1,
|
|
+ .cra_alignmask = sizeof(u32) - 1
|
|
+};
|
|
+static struct crypto_blkcipher chacha20_cipher = {
|
|
+ .base = {
|
|
+ .__crt_alg = &chacha20_alg
|
|
+ }
|
|
+};
|
|
+static struct blkcipher_desc chacha20_desc = {
|
|
+ .tfm = &chacha20_cipher
|
|
+};
|
|
+
|
|
+bool chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
|
|
+ const u8 *ad, const size_t ad_len,
|
|
+ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN])
|
|
+{
|
|
+ struct poly1305_ctx poly1305_state;
|
|
+ struct chacha20_ctx chacha20_state;
|
|
+ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 };
|
|
+ __le64 len;
|
|
+ __le64 le_nonce = cpu_to_le64(nonce);
|
|
+ bool have_simd = chacha20poly1305_init_simd();
|
|
+
|
|
+ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce);
|
|
+
|
|
+ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd);
|
|
+ poly1305_init(&poly1305_state, block0);
|
|
+ memzero_explicit(block0, sizeof(block0));
|
|
+
|
|
+ poly1305_update(&poly1305_state, ad, ad_len, have_simd);
|
|
+ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd);
|
|
+
|
|
+ chacha20_crypt(&chacha20_state, dst, src, src_len, have_simd);
|
|
+
|
|
+ poly1305_update(&poly1305_state, dst, src_len, have_simd);
|
|
+ poly1305_update(&poly1305_state, pad0, (0x10 - src_len) & 0xf, have_simd);
|
|
+
|
|
+ len = cpu_to_le64(ad_len);
|
|
+ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd);
|
|
+
|
|
+ len = cpu_to_le64(src_len);
|
|
+ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd);
|
|
+
|
|
+ poly1305_finish(&poly1305_state, dst + src_len);
|
|
+
|
|
+ memzero_explicit(&poly1305_state, sizeof(poly1305_state));
|
|
+ memzero_explicit(&chacha20_state, sizeof(chacha20_state));
|
|
+
|
|
+ chacha20poly1305_deinit_simd(have_simd);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool chacha20poly1305_encrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len,
|
|
+ const u8 *ad, const size_t ad_len,
|
|
+ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN],
|
|
+ bool have_simd)
|
|
+{
|
|
+ struct poly1305_ctx poly1305_state;
|
|
+ struct chacha20_ctx chacha20_state;
|
|
+ struct blkcipher_walk walk;
|
|
+ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 };
|
|
+ u8 mac[POLY1305_MAC_SIZE];
|
|
+ __le64 len;
|
|
+ __le64 le_nonce = cpu_to_le64(nonce);
|
|
+
|
|
+ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce);
|
|
+
|
|
+ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd);
|
|
+ poly1305_init(&poly1305_state, block0);
|
|
+ memzero_explicit(block0, sizeof(block0));
|
|
+
|
|
+ poly1305_update(&poly1305_state, ad, ad_len, have_simd);
|
|
+ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd);
|
|
+
|
|
+ if (likely(src_len)) {
|
|
+ blkcipher_walk_init(&walk, dst, src, src_len);
|
|
+ blkcipher_walk_virt_block(&chacha20_desc, &walk, CHACHA20_BLOCK_SIZE);
|
|
+ while (walk.nbytes >= CHACHA20_BLOCK_SIZE) {
|
|
+ size_t chunk_len = rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE);
|
|
+ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, chunk_len, have_simd);
|
|
+ poly1305_update(&poly1305_state, walk.dst.virt.addr, chunk_len, have_simd);
|
|
+ blkcipher_walk_done(&chacha20_desc, &walk, walk.nbytes % CHACHA20_BLOCK_SIZE);
|
|
+ }
|
|
+ if (walk.nbytes) {
|
|
+ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, have_simd);
|
|
+ poly1305_update(&poly1305_state, walk.dst.virt.addr, walk.nbytes, have_simd);
|
|
+ blkcipher_walk_done(&chacha20_desc, &walk, 0);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ poly1305_update(&poly1305_state, pad0, (0x10 - src_len) & 0xf, have_simd);
|
|
+
|
|
+ len = cpu_to_le64(ad_len);
|
|
+ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd);
|
|
+
|
|
+ len = cpu_to_le64(src_len);
|
|
+ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd);
|
|
+
|
|
+ poly1305_finish(&poly1305_state, mac);
|
|
+ scatterwalk_map_and_copy(mac, dst, src_len, sizeof(mac), 1);
|
|
+ memzero_explicit(&poly1305_state, sizeof(poly1305_state));
|
|
+ memzero_explicit(&chacha20_state, sizeof(chacha20_state));
|
|
+ memzero_explicit(mac, sizeof(mac));
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
|
|
+ const u8 *ad, const size_t ad_len,
|
|
+ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN])
|
|
+{
|
|
+ struct poly1305_ctx poly1305_state;
|
|
+ struct chacha20_ctx chacha20_state;
|
|
+ int ret;
|
|
+ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 };
|
|
+ u8 mac[POLY1305_MAC_SIZE];
|
|
+ size_t dst_len;
|
|
+ __le64 len;
|
|
+ __le64 le_nonce = cpu_to_le64(nonce);
|
|
+ bool have_simd;
|
|
+
|
|
+ if (unlikely(src_len < POLY1305_MAC_SIZE))
|
|
+ return false;
|
|
+
|
|
+ have_simd = chacha20poly1305_init_simd();
|
|
+
|
|
+ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce);
|
|
+
|
|
+ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd);
|
|
+ poly1305_init(&poly1305_state, block0);
|
|
+ memzero_explicit(block0, sizeof(block0));
|
|
+
|
|
+ poly1305_update(&poly1305_state, ad, ad_len, have_simd);
|
|
+ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd);
|
|
+
|
|
+ dst_len = src_len - POLY1305_MAC_SIZE;
|
|
+ poly1305_update(&poly1305_state, src, dst_len, have_simd);
|
|
+ poly1305_update(&poly1305_state, pad0, (0x10 - dst_len) & 0xf, have_simd);
|
|
+
|
|
+ len = cpu_to_le64(ad_len);
|
|
+ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd);
|
|
+
|
|
+ len = cpu_to_le64(dst_len);
|
|
+ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd);
|
|
+
|
|
+ poly1305_finish(&poly1305_state, mac);
|
|
+ memzero_explicit(&poly1305_state, sizeof(poly1305_state));
|
|
+
|
|
+ ret = crypto_memneq(mac, src + dst_len, POLY1305_MAC_SIZE);
|
|
+ memzero_explicit(mac, POLY1305_MAC_SIZE);
|
|
+ if (likely(!ret))
|
|
+ chacha20_crypt(&chacha20_state, dst, src, dst_len, have_simd);
|
|
+
|
|
+ memzero_explicit(&chacha20_state, sizeof(chacha20_state));
|
|
+
|
|
+ chacha20poly1305_deinit_simd(have_simd);
|
|
+ return !ret;
|
|
+}
|
|
+
|
|
+bool chacha20poly1305_decrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len,
|
|
+ const u8 *ad, const size_t ad_len,
|
|
+ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN])
|
|
+{
|
|
+ struct poly1305_ctx poly1305_state;
|
|
+ struct chacha20_ctx chacha20_state;
|
|
+ struct blkcipher_walk walk;
|
|
+ int ret;
|
|
+ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 };
|
|
+ u8 read_mac[POLY1305_MAC_SIZE], computed_mac[POLY1305_MAC_SIZE];
|
|
+ size_t dst_len;
|
|
+ __le64 len;
|
|
+ __le64 le_nonce = cpu_to_le64(nonce);
|
|
+ bool have_simd;
|
|
+
|
|
+ if (unlikely(src_len < POLY1305_MAC_SIZE))
|
|
+ return false;
|
|
+
|
|
+ have_simd = chacha20poly1305_init_simd();
|
|
+
|
|
+ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce);
|
|
+
|
|
+ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd);
|
|
+ poly1305_init(&poly1305_state, block0);
|
|
+ memzero_explicit(block0, sizeof(block0));
|
|
+
|
|
+ poly1305_update(&poly1305_state, ad, ad_len, have_simd);
|
|
+ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd);
|
|
+
|
|
+ dst_len = src_len - POLY1305_MAC_SIZE;
|
|
+ if (likely(dst_len)) {
|
|
+ blkcipher_walk_init(&walk, dst, src, dst_len);
|
|
+ blkcipher_walk_virt_block(&chacha20_desc, &walk, CHACHA20_BLOCK_SIZE);
|
|
+ while (walk.nbytes >= CHACHA20_BLOCK_SIZE) {
|
|
+ size_t chunk_len = rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE);
|
|
+ poly1305_update(&poly1305_state, walk.src.virt.addr, chunk_len, have_simd);
|
|
+ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, chunk_len, have_simd);
|
|
+ blkcipher_walk_done(&chacha20_desc, &walk, walk.nbytes % CHACHA20_BLOCK_SIZE);
|
|
+ }
|
|
+ if (walk.nbytes) {
|
|
+ poly1305_update(&poly1305_state, walk.src.virt.addr, walk.nbytes, have_simd);
|
|
+ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, have_simd);
|
|
+ blkcipher_walk_done(&chacha20_desc, &walk, 0);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ poly1305_update(&poly1305_state, pad0, (0x10 - dst_len) & 0xf, have_simd);
|
|
+
|
|
+ len = cpu_to_le64(ad_len);
|
|
+ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd);
|
|
+
|
|
+ len = cpu_to_le64(dst_len);
|
|
+ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd);
|
|
+
|
|
+ poly1305_finish(&poly1305_state, computed_mac);
|
|
+ memzero_explicit(&poly1305_state, sizeof(poly1305_state));
|
|
+
|
|
+ scatterwalk_map_and_copy(read_mac, src, dst_len, POLY1305_MAC_SIZE, 0);
|
|
+ ret = crypto_memneq(read_mac, computed_mac, POLY1305_MAC_SIZE);
|
|
+ memzero_explicit(read_mac, POLY1305_MAC_SIZE);
|
|
+ memzero_explicit(computed_mac, POLY1305_MAC_SIZE);
|
|
+ memzero_explicit(&chacha20_state, sizeof(chacha20_state));
|
|
+ chacha20poly1305_deinit_simd(have_simd);
|
|
+ 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"
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/curve25519.c
|
|
@@ -0,0 +1,1240 @@
|
|
+/* Original author: Adam Langley <agl@imperialviolet.org>
|
|
+ *
|
|
+ * Copyright 2008 Google Inc. All Rights Reserved.
|
|
+ * Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ */
|
|
+
|
|
+#include "curve25519.h"
|
|
+
|
|
+#include <linux/string.h>
|
|
+#include <linux/random.h>
|
|
+#include <crypto/algapi.h>
|
|
+
|
|
+static __always_inline void normalize_secret(u8 secret[CURVE25519_POINT_SIZE])
|
|
+{
|
|
+ secret[0] &= 248;
|
|
+ secret[31] &= 127;
|
|
+ secret[31] |= 64;
|
|
+}
|
|
+
|
|
+#ifdef __SIZEOF_INT128__
|
|
+typedef u64 limb;
|
|
+typedef limb felem[5];
|
|
+typedef __uint128_t uint128_t;
|
|
+
|
|
+/* Sum two numbers: output += in */
|
|
+static __always_inline void fsum(limb *output, const limb *in)
|
|
+{
|
|
+ output[0] += in[0];
|
|
+ output[1] += in[1];
|
|
+ output[2] += in[2];
|
|
+ output[3] += in[3];
|
|
+ output[4] += in[4];
|
|
+}
|
|
+
|
|
+/* Find the difference of two numbers: output = in - output
|
|
+ * (note the order of the arguments!)
|
|
+ *
|
|
+ * Assumes that out[i] < 2**52
|
|
+ * On return, out[i] < 2**55
|
|
+ */
|
|
+static __always_inline void fdifference_backwards(felem out, const felem in)
|
|
+{
|
|
+ /* 152 is 19 << 3 */
|
|
+ static const limb two54m152 = (((limb)1) << 54) - 152;
|
|
+ static const limb two54m8 = (((limb)1) << 54) - 8;
|
|
+
|
|
+ out[0] = in[0] + two54m152 - out[0];
|
|
+ out[1] = in[1] + two54m8 - out[1];
|
|
+ out[2] = in[2] + two54m8 - out[2];
|
|
+ out[3] = in[3] + two54m8 - out[3];
|
|
+ out[4] = in[4] + two54m8 - out[4];
|
|
+}
|
|
+
|
|
+/* Multiply a number by a scalar: output = in * scalar */
|
|
+static __always_inline void fscalar_product(felem output, const felem in, const limb scalar)
|
|
+{
|
|
+ uint128_t a;
|
|
+
|
|
+ a = ((uint128_t) in[0]) * scalar;
|
|
+ output[0] = ((limb)a) & 0x7ffffffffffffUL;
|
|
+
|
|
+ a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51));
|
|
+ output[1] = ((limb)a) & 0x7ffffffffffffUL;
|
|
+
|
|
+ a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51));
|
|
+ output[2] = ((limb)a) & 0x7ffffffffffffUL;
|
|
+
|
|
+ a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51));
|
|
+ output[3] = ((limb)a) & 0x7ffffffffffffUL;
|
|
+
|
|
+ a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51));
|
|
+ output[4] = ((limb)a) & 0x7ffffffffffffUL;
|
|
+
|
|
+ output[0] += (a >> 51) * 19;
|
|
+}
|
|
+
|
|
+/* Multiply two numbers: output = in2 * in
|
|
+ *
|
|
+ * output must be distinct to both inputs. The inputs are reduced coefficient
|
|
+ * form, the output is not.
|
|
+ *
|
|
+ * Assumes that in[i] < 2**55 and likewise for in2.
|
|
+ * On return, output[i] < 2**52
|
|
+ */
|
|
+static __always_inline void fmul(felem output, const felem in2, const felem in)
|
|
+{
|
|
+ uint128_t t[5];
|
|
+ limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;
|
|
+
|
|
+ r0 = in[0];
|
|
+ r1 = in[1];
|
|
+ r2 = in[2];
|
|
+ r3 = in[3];
|
|
+ r4 = in[4];
|
|
+
|
|
+ s0 = in2[0];
|
|
+ s1 = in2[1];
|
|
+ s2 = in2[2];
|
|
+ s3 = in2[3];
|
|
+ s4 = in2[4];
|
|
+
|
|
+ t[0] = ((uint128_t) r0) * s0;
|
|
+ t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0;
|
|
+ t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1;
|
|
+ t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1;
|
|
+ t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2;
|
|
+
|
|
+ r4 *= 19;
|
|
+ r1 *= 19;
|
|
+ r2 *= 19;
|
|
+ r3 *= 19;
|
|
+
|
|
+ t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2;
|
|
+ t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3;
|
|
+ t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4;
|
|
+ t[3] += ((uint128_t) r4) * s4;
|
|
+
|
|
+ r0 = (limb)t[0] & 0x7ffffffffffffUL; c = (limb)(t[0] >> 51);
|
|
+ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffffUL; c = (limb)(t[1] >> 51);
|
|
+ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffffUL; c = (limb)(t[2] >> 51);
|
|
+ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffffUL; c = (limb)(t[3] >> 51);
|
|
+ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffffUL; c = (limb)(t[4] >> 51);
|
|
+ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffffUL;
|
|
+ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffffUL;
|
|
+ r2 += c;
|
|
+
|
|
+ output[0] = r0;
|
|
+ output[1] = r1;
|
|
+ output[2] = r2;
|
|
+ output[3] = r3;
|
|
+ output[4] = r4;
|
|
+}
|
|
+
|
|
+static __always_inline void fsquare_times(felem output, const felem in, limb count)
|
|
+{
|
|
+ uint128_t t[5];
|
|
+ limb r0,r1,r2,r3,r4,c;
|
|
+ limb d0,d1,d2,d4,d419;
|
|
+
|
|
+ r0 = in[0];
|
|
+ r1 = in[1];
|
|
+ r2 = in[2];
|
|
+ r3 = in[3];
|
|
+ r4 = in[4];
|
|
+
|
|
+ do {
|
|
+ d0 = r0 * 2;
|
|
+ d1 = r1 * 2;
|
|
+ d2 = r2 * 2 * 19;
|
|
+ d419 = r4 * 19;
|
|
+ d4 = d419 * 2;
|
|
+
|
|
+ t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 ));
|
|
+ t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19));
|
|
+ t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 ));
|
|
+ t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 ));
|
|
+ t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 ));
|
|
+
|
|
+ r0 = (limb)t[0] & 0x7ffffffffffffUL; c = (limb)(t[0] >> 51);
|
|
+ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffffUL; c = (limb)(t[1] >> 51);
|
|
+ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffffUL; c = (limb)(t[2] >> 51);
|
|
+ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffffUL; c = (limb)(t[3] >> 51);
|
|
+ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffffUL; c = (limb)(t[4] >> 51);
|
|
+ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffffUL;
|
|
+ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffffUL;
|
|
+ r2 += c;
|
|
+ } while(--count);
|
|
+
|
|
+ output[0] = r0;
|
|
+ output[1] = r1;
|
|
+ output[2] = r2;
|
|
+ output[3] = r3;
|
|
+ output[4] = r4;
|
|
+}
|
|
+
|
|
+/* Load a little-endian 64-bit number */
|
|
+static inline limb load_limb(const u8 *in)
|
|
+{
|
|
+ return le64_to_cpu(*(u64 *)in);
|
|
+}
|
|
+
|
|
+static inline void store_limb(u8 *out, limb in)
|
|
+{
|
|
+ *(u64 *)out = cpu_to_le64(in);
|
|
+}
|
|
+
|
|
+/* Take a little-endian, 32-byte number and expand it into polynomial form */
|
|
+static inline void fexpand(limb *output, const u8 *in)
|
|
+{
|
|
+ output[0] = load_limb(in) & 0x7ffffffffffffUL;
|
|
+ output[1] = (load_limb(in + 6) >> 3) & 0x7ffffffffffffUL;
|
|
+ output[2] = (load_limb(in + 12) >> 6) & 0x7ffffffffffffUL;
|
|
+ output[3] = (load_limb(in + 19) >> 1) & 0x7ffffffffffffUL;
|
|
+ output[4] = (load_limb(in + 24) >> 12) & 0x7ffffffffffffUL;
|
|
+}
|
|
+
|
|
+/* Take a fully reduced polynomial form number and contract it into a
|
|
+ * little-endian, 32-byte array
|
|
+ */
|
|
+static void fcontract(u8 *output, const felem input)
|
|
+{
|
|
+ uint128_t t[5];
|
|
+
|
|
+ t[0] = input[0];
|
|
+ t[1] = input[1];
|
|
+ t[2] = input[2];
|
|
+ t[3] = input[3];
|
|
+ t[4] = input[4];
|
|
+
|
|
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL;
|
|
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL;
|
|
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL;
|
|
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL;
|
|
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL;
|
|
+
|
|
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL;
|
|
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL;
|
|
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL;
|
|
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL;
|
|
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL;
|
|
+
|
|
+ /* now t is between 0 and 2^255-1, properly carried. */
|
|
+ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */
|
|
+
|
|
+ t[0] += 19;
|
|
+
|
|
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL;
|
|
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL;
|
|
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL;
|
|
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL;
|
|
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL;
|
|
+
|
|
+ /* now between 19 and 2^255-1 in both cases, and offset by 19. */
|
|
+
|
|
+ t[0] += 0x8000000000000UL - 19;
|
|
+ t[1] += 0x8000000000000UL - 1;
|
|
+ t[2] += 0x8000000000000UL - 1;
|
|
+ t[3] += 0x8000000000000UL - 1;
|
|
+ t[4] += 0x8000000000000UL - 1;
|
|
+
|
|
+ /* now between 2^255 and 2^256-20, and offset by 2^255. */
|
|
+
|
|
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL;
|
|
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL;
|
|
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL;
|
|
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL;
|
|
+ t[4] &= 0x7ffffffffffffUL;
|
|
+
|
|
+ store_limb(output, t[0] | (t[1] << 51));
|
|
+ store_limb(output+8, (t[1] >> 13) | (t[2] << 38));
|
|
+ store_limb(output+16, (t[2] >> 26) | (t[3] << 25));
|
|
+ store_limb(output+24, (t[3] >> 39) | (t[4] << 12));
|
|
+}
|
|
+
|
|
+/* Input: Q, Q', Q-Q'
|
|
+ * Output: 2Q, Q+Q'
|
|
+ *
|
|
+ * x2 z3: long form
|
|
+ * x3 z3: long form
|
|
+ * x z: short form, destroyed
|
|
+ * xprime zprime: short form, destroyed
|
|
+ * qmqp: short form, preserved
|
|
+ */
|
|
+static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
|
+ limb *x3, limb *z3, /* output Q + Q' */
|
|
+ limb *x, limb *z, /* input Q */
|
|
+ limb *xprime, limb *zprime, /* input Q' */
|
|
+ const limb *qmqp /* input Q - Q' */)
|
|
+{
|
|
+ limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5], zzprime[5], zzzprime[5];
|
|
+
|
|
+ memcpy(origx, x, 5 * sizeof(limb));
|
|
+ fsum(x, z);
|
|
+ fdifference_backwards(z, origx); // does x - z
|
|
+
|
|
+ memcpy(origxprime, xprime, sizeof(limb) * 5);
|
|
+ fsum(xprime, zprime);
|
|
+ fdifference_backwards(zprime, origxprime);
|
|
+ fmul(xxprime, xprime, z);
|
|
+ fmul(zzprime, x, zprime);
|
|
+ memcpy(origxprime, xxprime, sizeof(limb) * 5);
|
|
+ fsum(xxprime, zzprime);
|
|
+ fdifference_backwards(zzprime, origxprime);
|
|
+ fsquare_times(x3, xxprime, 1);
|
|
+ fsquare_times(zzzprime, zzprime, 1);
|
|
+ fmul(z3, zzzprime, qmqp);
|
|
+
|
|
+ fsquare_times(xx, x, 1);
|
|
+ fsquare_times(zz, z, 1);
|
|
+ fmul(x2, xx, zz);
|
|
+ fdifference_backwards(zz, xx); // does zz = xx - zz
|
|
+ fscalar_product(zzz, zz, 121665);
|
|
+ fsum(zzz, xx);
|
|
+ fmul(z2, zz, zzz);
|
|
+}
|
|
+
|
|
+/* Maybe swap the contents of two limb arrays (@a and @b), each @len elements
|
|
+ * long. Perform the swap iff @swap is non-zero.
|
|
+ *
|
|
+ * This function performs the swap without leaking any side-channel
|
|
+ * information.
|
|
+ */
|
|
+static void swap_conditional(limb a[5], limb b[5], limb iswap)
|
|
+{
|
|
+ unsigned i;
|
|
+ const limb swap = -iswap;
|
|
+
|
|
+ for (i = 0; i < 5; ++i) {
|
|
+ const limb x = swap & (a[i] ^ b[i]);
|
|
+ a[i] ^= x;
|
|
+ b[i] ^= x;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Calculates nQ where Q is the x-coordinate of a point on the curve
|
|
+ *
|
|
+ * resultx/resultz: the x coordinate of the resulting curve point (short form)
|
|
+ * n: a little endian, 32-byte number
|
|
+ * q: a point of the curve (short form)
|
|
+ */
|
|
+static void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q)
|
|
+{
|
|
+ limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0};
|
|
+ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
|
|
+ limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1};
|
|
+ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
|
|
+
|
|
+ unsigned i, j;
|
|
+
|
|
+ memcpy(nqpqx, q, sizeof(limb) * 5);
|
|
+
|
|
+ for (i = 0; i < 32; ++i) {
|
|
+ u8 byte = n[31 - i];
|
|
+ for (j = 0; j < 8; ++j) {
|
|
+ const limb bit = byte >> 7;
|
|
+
|
|
+ swap_conditional(nqx, nqpqx, bit);
|
|
+ swap_conditional(nqz, nqpqz, bit);
|
|
+ fmonty(nqx2, nqz2,
|
|
+ nqpqx2, nqpqz2,
|
|
+ nqx, nqz,
|
|
+ nqpqx, nqpqz,
|
|
+ q);
|
|
+ swap_conditional(nqx2, nqpqx2, bit);
|
|
+ swap_conditional(nqz2, nqpqz2, bit);
|
|
+
|
|
+ t = nqx;
|
|
+ nqx = nqx2;
|
|
+ nqx2 = t;
|
|
+ t = nqz;
|
|
+ nqz = nqz2;
|
|
+ nqz2 = t;
|
|
+ t = nqpqx;
|
|
+ nqpqx = nqpqx2;
|
|
+ nqpqx2 = t;
|
|
+ t = nqpqz;
|
|
+ nqpqz = nqpqz2;
|
|
+ nqpqz2 = t;
|
|
+
|
|
+ byte <<= 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ memcpy(resultx, nqx, sizeof(limb) * 5);
|
|
+ memcpy(resultz, nqz, sizeof(limb) * 5);
|
|
+}
|
|
+
|
|
+static void crecip(felem out, const felem z)
|
|
+{
|
|
+ felem a,t0,b,c;
|
|
+
|
|
+ /* 2 */ fsquare_times(a, z, 1); // a = 2
|
|
+ /* 8 */ fsquare_times(t0, a, 2);
|
|
+ /* 9 */ fmul(b, t0, z); // b = 9
|
|
+ /* 11 */ fmul(a, b, a); // a = 11
|
|
+ /* 22 */ fsquare_times(t0, a, 1);
|
|
+ /* 2^5 - 2^0 = 31 */ fmul(b, t0, b);
|
|
+ /* 2^10 - 2^5 */ fsquare_times(t0, b, 5);
|
|
+ /* 2^10 - 2^0 */ fmul(b, t0, b);
|
|
+ /* 2^20 - 2^10 */ fsquare_times(t0, b, 10);
|
|
+ /* 2^20 - 2^0 */ fmul(c, t0, b);
|
|
+ /* 2^40 - 2^20 */ fsquare_times(t0, c, 20);
|
|
+ /* 2^40 - 2^0 */ fmul(t0, t0, c);
|
|
+ /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10);
|
|
+ /* 2^50 - 2^0 */ fmul(b, t0, b);
|
|
+ /* 2^100 - 2^50 */ fsquare_times(t0, b, 50);
|
|
+ /* 2^100 - 2^0 */ fmul(c, t0, b);
|
|
+ /* 2^200 - 2^100 */ fsquare_times(t0, c, 100);
|
|
+ /* 2^200 - 2^0 */ fmul(t0, t0, c);
|
|
+ /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50);
|
|
+ /* 2^250 - 2^0 */ fmul(t0, t0, b);
|
|
+ /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5);
|
|
+ /* 2^255 - 21 */ fmul(out, t0, a);
|
|
+}
|
|
+
|
|
+void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE])
|
|
+{
|
|
+ limb bp[5], x[5], z[5], zmone[5];
|
|
+ u8 e[32];
|
|
+
|
|
+ memcpy(e, secret, 32);
|
|
+ normalize_secret(e);
|
|
+
|
|
+ fexpand(bp, basepoint);
|
|
+ cmult(x, z, e, bp);
|
|
+ crecip(zmone, z);
|
|
+ fmul(z, x, zmone);
|
|
+ fcontract(mypublic, z);
|
|
+
|
|
+ memzero_explicit(e, sizeof(e));
|
|
+ memzero_explicit(bp, sizeof(bp));
|
|
+ memzero_explicit(x, sizeof(x));
|
|
+ memzero_explicit(z, sizeof(z));
|
|
+ memzero_explicit(zmone, sizeof(zmone));
|
|
+}
|
|
+
|
|
+#else
|
|
+typedef s64 limb;
|
|
+
|
|
+/* Field element representation:
|
|
+ *
|
|
+ * Field elements are written as an array of signed, 64-bit limbs, least
|
|
+ * significant first. The value of the field element is:
|
|
+ * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
|
|
+ *
|
|
+ * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */
|
|
+
|
|
+/* Sum two numbers: output += in */
|
|
+static void fsum(limb *output, const limb *in)
|
|
+{
|
|
+ unsigned i;
|
|
+ for (i = 0; i < 10; i += 2) {
|
|
+ output[0 + i] = output[0 + i] + in[0 + i];
|
|
+ output[1 + i] = output[1 + i] + in[1 + i];
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Find the difference of two numbers: output = in - output
|
|
+ * (note the order of the arguments!). */
|
|
+static void fdifference(limb *output, const limb *in)
|
|
+{
|
|
+ unsigned i;
|
|
+ for (i = 0; i < 10; ++i)
|
|
+ output[i] = in[i] - output[i];
|
|
+}
|
|
+
|
|
+/* Multiply a number by a scalar: output = in * scalar */
|
|
+static void fscalar_product(limb *output, const limb *in, const limb scalar)
|
|
+{
|
|
+ unsigned i;
|
|
+ for (i = 0; i < 10; ++i)
|
|
+ output[i] = in[i] * scalar;
|
|
+}
|
|
+
|
|
+/* Multiply two numbers: output = in2 * in
|
|
+ *
|
|
+ * output must be distinct to both inputs. The inputs are reduced coefficient
|
|
+ * form, the output is not.
|
|
+ *
|
|
+ * output[x] <= 14 * the largest product of the input limbs. */
|
|
+static void fproduct(limb *output, const limb *in2, const limb *in)
|
|
+{
|
|
+ output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
|
|
+ output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
|
|
+ ((limb) ((s32) in2[1])) * ((s32) in[0]);
|
|
+ output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
|
|
+ ((limb) ((s32) in2[0])) * ((s32) in[2]) +
|
|
+ ((limb) ((s32) in2[2])) * ((s32) in[0]);
|
|
+ output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
|
|
+ ((limb) ((s32) in2[2])) * ((s32) in[1]) +
|
|
+ ((limb) ((s32) in2[0])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[3])) * ((s32) in[0]);
|
|
+ output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
|
|
+ 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[3])) * ((s32) in[1])) +
|
|
+ ((limb) ((s32) in2[0])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in2[4])) * ((s32) in[0]);
|
|
+ output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[3])) * ((s32) in[2]) +
|
|
+ ((limb) ((s32) in2[1])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in2[4])) * ((s32) in[1]) +
|
|
+ ((limb) ((s32) in2[0])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[5])) * ((s32) in[0]);
|
|
+ output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[1])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[5])) * ((s32) in[1])) +
|
|
+ ((limb) ((s32) in2[2])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in2[4])) * ((s32) in[2]) +
|
|
+ ((limb) ((s32) in2[0])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in2[6])) * ((s32) in[0]);
|
|
+ output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in2[4])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[2])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[5])) * ((s32) in[2]) +
|
|
+ ((limb) ((s32) in2[1])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in2[6])) * ((s32) in[1]) +
|
|
+ ((limb) ((s32) in2[0])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[7])) * ((s32) in[0]);
|
|
+ output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
|
|
+ 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[5])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[1])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[7])) * ((s32) in[1])) +
|
|
+ ((limb) ((s32) in2[2])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in2[6])) * ((s32) in[2]) +
|
|
+ ((limb) ((s32) in2[0])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in2[8])) * ((s32) in[0]);
|
|
+ output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[5])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in2[3])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in2[6])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[2])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[7])) * ((s32) in[2]) +
|
|
+ ((limb) ((s32) in2[1])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in2[8])) * ((s32) in[1]) +
|
|
+ ((limb) ((s32) in2[0])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[0]);
|
|
+ output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[3])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[7])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[1])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[1])) +
|
|
+ ((limb) ((s32) in2[4])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in2[6])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in2[2])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in2[8])) * ((s32) in[2]);
|
|
+ output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in2[6])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[4])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[7])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in2[3])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in2[8])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in2[2])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[2]);
|
|
+ output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
|
|
+ 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[7])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[3])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[3])) +
|
|
+ ((limb) ((s32) in2[4])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in2[8])) * ((s32) in[4]);
|
|
+ output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[7])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in2[5])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in2[8])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in2[4])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[4]);
|
|
+ output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[5])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[5])) +
|
|
+ ((limb) ((s32) in2[6])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in2[8])) * ((s32) in[6]);
|
|
+ output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in2[8])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in2[6])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[6]);
|
|
+ output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
|
|
+ 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[7]));
|
|
+ output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
|
|
+ ((limb) ((s32) in2[9])) * ((s32) in[8]);
|
|
+ output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
|
|
+}
|
|
+
|
|
+/* Reduce a long form to a short form by taking the input mod 2^255 - 19.
|
|
+ *
|
|
+ * On entry: |output[i]| < 14*2^54
|
|
+ * On exit: |output[0..8]| < 280*2^54 */
|
|
+static void freduce_degree(limb *output)
|
|
+{
|
|
+ /* Each of these shifts and adds ends up multiplying the value by 19.
|
|
+ *
|
|
+ * For output[0..8], the absolute entry value is < 14*2^54 and we add, at
|
|
+ * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */
|
|
+ output[8] += output[18] << 4;
|
|
+ output[8] += output[18] << 1;
|
|
+ output[8] += output[18];
|
|
+ output[7] += output[17] << 4;
|
|
+ output[7] += output[17] << 1;
|
|
+ output[7] += output[17];
|
|
+ output[6] += output[16] << 4;
|
|
+ output[6] += output[16] << 1;
|
|
+ output[6] += output[16];
|
|
+ output[5] += output[15] << 4;
|
|
+ output[5] += output[15] << 1;
|
|
+ output[5] += output[15];
|
|
+ output[4] += output[14] << 4;
|
|
+ output[4] += output[14] << 1;
|
|
+ output[4] += output[14];
|
|
+ output[3] += output[13] << 4;
|
|
+ output[3] += output[13] << 1;
|
|
+ output[3] += output[13];
|
|
+ output[2] += output[12] << 4;
|
|
+ output[2] += output[12] << 1;
|
|
+ output[2] += output[12];
|
|
+ output[1] += output[11] << 4;
|
|
+ output[1] += output[11] << 1;
|
|
+ output[1] += output[11];
|
|
+ output[0] += output[10] << 4;
|
|
+ output[0] += output[10] << 1;
|
|
+ output[0] += output[10];
|
|
+}
|
|
+
|
|
+#if (-1 & 3) != 3
|
|
+#error "This code only works on a two's complement system"
|
|
+#endif
|
|
+
|
|
+/* return v / 2^26, using only shifts and adds.
|
|
+ *
|
|
+ * On entry: v can take any value. */
|
|
+static inline limb div_by_2_26(const limb v)
|
|
+{
|
|
+ /* High word of v; no shift needed. */
|
|
+ const u32 highword = (u32) (((u64) v) >> 32);
|
|
+ /* Set to all 1s if v was negative; else set to 0s. */
|
|
+ const s32 sign = ((s32) highword) >> 31;
|
|
+ /* Set to 0x3ffffff if v was negative; else set to 0. */
|
|
+ const s32 roundoff = ((u32) sign) >> 6;
|
|
+ /* Should return v / (1<<26) */
|
|
+ return (v + roundoff) >> 26;
|
|
+}
|
|
+
|
|
+/* return v / (2^25), using only shifts and adds.
|
|
+ *
|
|
+ * On entry: v can take any value. */
|
|
+static inline limb div_by_2_25(const limb v)
|
|
+{
|
|
+ /* High word of v; no shift needed*/
|
|
+ const u32 highword = (u32) (((u64) v) >> 32);
|
|
+ /* Set to all 1s if v was negative; else set to 0s. */
|
|
+ const s32 sign = ((s32) highword) >> 31;
|
|
+ /* Set to 0x1ffffff if v was negative; else set to 0. */
|
|
+ const s32 roundoff = ((u32) sign) >> 7;
|
|
+ /* Should return v / (1<<25) */
|
|
+ return (v + roundoff) >> 25;
|
|
+}
|
|
+
|
|
+/* Reduce all coefficients of the short form input so that |x| < 2^26.
|
|
+ *
|
|
+ * On entry: |output[i]| < 280*2^54 */
|
|
+static void freduce_coefficients(limb *output)
|
|
+{
|
|
+ unsigned i;
|
|
+
|
|
+ output[10] = 0;
|
|
+
|
|
+ for (i = 0; i < 10; i += 2) {
|
|
+ limb over = div_by_2_26(output[i]);
|
|
+ /* The entry condition (that |output[i]| < 280*2^54) means that over is, at
|
|
+ * most, 280*2^28 in the first iteration of this loop. This is added to the
|
|
+ * next limb and we can approximate the resulting bound of that limb by
|
|
+ * 281*2^54. */
|
|
+ output[i] -= over << 26;
|
|
+ output[i+1] += over;
|
|
+
|
|
+ /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| <
|
|
+ * 281*2^29. When this is added to the next limb, the resulting bound can
|
|
+ * be approximated as 281*2^54.
|
|
+ *
|
|
+ * For subsequent iterations of the loop, 281*2^54 remains a conservative
|
|
+ * bound and no overflow occurs. */
|
|
+ over = div_by_2_25(output[i+1]);
|
|
+ output[i+1] -= over << 25;
|
|
+ output[i+2] += over;
|
|
+ }
|
|
+ /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */
|
|
+ output[0] += output[10] << 4;
|
|
+ output[0] += output[10] << 1;
|
|
+ output[0] += output[10];
|
|
+
|
|
+ output[10] = 0;
|
|
+
|
|
+ /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29
|
|
+ * So |over| will be no more than 2^16. */
|
|
+ {
|
|
+ limb over = div_by_2_26(output[0]);
|
|
+ output[0] -= over << 26;
|
|
+ output[1] += over;
|
|
+ }
|
|
+
|
|
+ /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The
|
|
+ * bound on |output[1]| is sufficient to meet our needs. */
|
|
+}
|
|
+
|
|
+/* A helpful wrapper around fproduct: output = in * in2.
|
|
+ *
|
|
+ * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27.
|
|
+ *
|
|
+ * output must be distinct to both inputs. The output is reduced degree
|
|
+ * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */
|
|
+static void fmul(limb *output, const limb *in, const limb *in2)
|
|
+{
|
|
+ limb t[19];
|
|
+ fproduct(t, in, in2);
|
|
+ /* |t[i]| < 14*2^54 */
|
|
+ freduce_degree(t);
|
|
+ freduce_coefficients(t);
|
|
+ /* |t[i]| < 2^26 */
|
|
+ memcpy(output, t, sizeof(limb) * 10);
|
|
+}
|
|
+
|
|
+/* Square a number: output = in**2
|
|
+ *
|
|
+ * output must be distinct from the input. The inputs are reduced coefficient
|
|
+ * form, the output is not.
|
|
+ *
|
|
+ * output[x] <= 14 * the largest product of the input limbs. */
|
|
+static void fsquare_inner(limb *output, const limb *in)
|
|
+{
|
|
+ output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
|
|
+ output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
|
|
+ output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
|
|
+ ((limb) ((s32) in[0])) * ((s32) in[2]));
|
|
+ output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
|
|
+ ((limb) ((s32) in[0])) * ((s32) in[3]));
|
|
+ output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
|
|
+ 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
|
|
+ 2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
|
|
+ output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in[1])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in[0])) * ((s32) in[5]));
|
|
+ output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
|
|
+ ((limb) ((s32) in[2])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in[0])) * ((s32) in[6]) +
|
|
+ 2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
|
|
+ output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
|
|
+ ((limb) ((s32) in[2])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in[1])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in[0])) * ((s32) in[7]));
|
|
+ output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
|
|
+ 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in[0])) * ((s32) in[8]) +
|
|
+ 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in[3])) * ((s32) in[5])));
|
|
+ output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in[3])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in[2])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in[1])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in[0])) * ((s32) in[9]));
|
|
+ output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
|
|
+ ((limb) ((s32) in[4])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in[2])) * ((s32) in[8]) +
|
|
+ 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in[1])) * ((s32) in[9])));
|
|
+ output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
|
|
+ ((limb) ((s32) in[4])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in[3])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in[2])) * ((s32) in[9]));
|
|
+ output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
|
|
+ 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
|
|
+ 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in[3])) * ((s32) in[9])));
|
|
+ output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in[5])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in[4])) * ((s32) in[9]));
|
|
+ output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
|
|
+ ((limb) ((s32) in[6])) * ((s32) in[8]) +
|
|
+ 2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
|
|
+ output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
|
|
+ ((limb) ((s32) in[6])) * ((s32) in[9]));
|
|
+ output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
|
|
+ 4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
|
|
+ output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
|
|
+ output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
|
|
+}
|
|
+
|
|
+/* fsquare sets output = in^2.
|
|
+ *
|
|
+ * On entry: The |in| argument is in reduced coefficients form and |in[i]| <
|
|
+ * 2^27.
|
|
+ *
|
|
+ * On exit: The |output| argument is in reduced coefficients form (indeed, one
|
|
+ * need only provide storage for 10 limbs) and |out[i]| < 2^26. */
|
|
+static void fsquare(limb *output, const limb *in)
|
|
+{
|
|
+ limb t[19];
|
|
+ fsquare_inner(t, in);
|
|
+ /* |t[i]| < 14*2^54 because the largest product of two limbs will be <
|
|
+ * 2^(27+27) and fsquare_inner adds together, at most, 14 of those
|
|
+ * products. */
|
|
+ freduce_degree(t);
|
|
+ freduce_coefficients(t);
|
|
+ /* |t[i]| < 2^26 */
|
|
+ memcpy(output, t, sizeof(limb) * 10);
|
|
+}
|
|
+
|
|
+/* Take a little-endian, 32-byte number and expand it into polynomial form */
|
|
+static inline void fexpand(limb *output, const u8 *input)
|
|
+{
|
|
+#define F(n,start,shift,mask) \
|
|
+ output[n] = ((((limb) input[start + 0]) | \
|
|
+ ((limb) input[start + 1]) << 8 | \
|
|
+ ((limb) input[start + 2]) << 16 | \
|
|
+ ((limb) input[start + 3]) << 24) >> shift) & mask;
|
|
+ F(0, 0, 0, 0x3ffffff);
|
|
+ F(1, 3, 2, 0x1ffffff);
|
|
+ F(2, 6, 3, 0x3ffffff);
|
|
+ F(3, 9, 5, 0x1ffffff);
|
|
+ F(4, 12, 6, 0x3ffffff);
|
|
+ F(5, 16, 0, 0x1ffffff);
|
|
+ F(6, 19, 1, 0x3ffffff);
|
|
+ F(7, 22, 3, 0x1ffffff);
|
|
+ F(8, 25, 4, 0x3ffffff);
|
|
+ F(9, 28, 6, 0x1ffffff);
|
|
+#undef F
|
|
+}
|
|
+
|
|
+#if (-32 >> 1) != -16
|
|
+#error "This code only works when >> does sign-extension on negative numbers"
|
|
+#endif
|
|
+
|
|
+/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */
|
|
+static s32 s32_eq(s32 a, s32 b)
|
|
+{
|
|
+ a = ~(a ^ b);
|
|
+ a &= a << 16;
|
|
+ a &= a << 8;
|
|
+ a &= a << 4;
|
|
+ a &= a << 2;
|
|
+ a &= a << 1;
|
|
+ return a >> 31;
|
|
+}
|
|
+
|
|
+/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are
|
|
+ * both non-negative. */
|
|
+static s32 s32_gte(s32 a, s32 b)
|
|
+{
|
|
+ a -= b;
|
|
+ /* a >= 0 iff a >= b. */
|
|
+ return ~(a >> 31);
|
|
+}
|
|
+
|
|
+/* Take a fully reduced polynomial form number and contract it into a
|
|
+ * little-endian, 32-byte array.
|
|
+ *
|
|
+ * On entry: |input_limbs[i]| < 2^26 */
|
|
+static void fcontract(u8 *output, limb *input_limbs)
|
|
+{
|
|
+ int i;
|
|
+ int j;
|
|
+ s32 input[10];
|
|
+ s32 mask;
|
|
+
|
|
+ /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */
|
|
+ for (i = 0; i < 10; i++) {
|
|
+ input[i] = input_limbs[i];
|
|
+ }
|
|
+
|
|
+ for (j = 0; j < 2; ++j) {
|
|
+ for (i = 0; i < 9; ++i) {
|
|
+ if ((i & 1) == 1) {
|
|
+ /* This calculation is a time-invariant way to make input[i]
|
|
+ * non-negative by borrowing from the next-larger limb. */
|
|
+ const s32 mask = input[i] >> 31;
|
|
+ const s32 carry = -((input[i] & mask) >> 25);
|
|
+ input[i] = input[i] + (carry << 25);
|
|
+ input[i+1] = input[i+1] - carry;
|
|
+ } else {
|
|
+ const s32 mask = input[i] >> 31;
|
|
+ const s32 carry = -((input[i] & mask) >> 26);
|
|
+ input[i] = input[i] + (carry << 26);
|
|
+ input[i+1] = input[i+1] - carry;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* There's no greater limb for input[9] to borrow from, but we can multiply
|
|
+ * by 19 and borrow from input[0], which is valid mod 2^255-19. */
|
|
+ {
|
|
+ const s32 mask = input[9] >> 31;
|
|
+ const s32 carry = -((input[9] & mask) >> 25);
|
|
+ input[9] = input[9] + (carry << 25);
|
|
+ input[0] = input[0] - (carry * 19);
|
|
+ }
|
|
+
|
|
+ /* After the first iteration, input[1..9] are non-negative and fit within
|
|
+ * 25 or 26 bits, depending on position. However, input[0] may be
|
|
+ * negative. */
|
|
+ }
|
|
+
|
|
+ /* The first borrow-propagation pass above ended with every limb
|
|
+ except (possibly) input[0] non-negative.
|
|
+ If input[0] was negative after the first pass, then it was because of a
|
|
+ carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most,
|
|
+ one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19.
|
|
+ In the second pass, each limb is decreased by at most one. Thus the second
|
|
+ borrow-propagation pass could only have wrapped around to decrease
|
|
+ input[0] again if the first pass left input[0] negative *and* input[1]
|
|
+ through input[9] were all zero. In that case, input[1] is now 2^25 - 1,
|
|
+ and this last borrow-propagation step will leave input[1] non-negative. */
|
|
+ {
|
|
+ const s32 mask = input[0] >> 31;
|
|
+ const s32 carry = -((input[0] & mask) >> 26);
|
|
+ input[0] = input[0] + (carry << 26);
|
|
+ input[1] = input[1] - carry;
|
|
+ }
|
|
+
|
|
+ /* All input[i] are now non-negative. However, there might be values between
|
|
+ * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */
|
|
+ for (j = 0; j < 2; j++) {
|
|
+ for (i = 0; i < 9; i++) {
|
|
+ if ((i & 1) == 1) {
|
|
+ const s32 carry = input[i] >> 25;
|
|
+ input[i] &= 0x1ffffff;
|
|
+ input[i+1] += carry;
|
|
+ } else {
|
|
+ const s32 carry = input[i] >> 26;
|
|
+ input[i] &= 0x3ffffff;
|
|
+ input[i+1] += carry;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ {
|
|
+ const s32 carry = input[9] >> 25;
|
|
+ input[9] &= 0x1ffffff;
|
|
+ input[0] += 19*carry;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* If the first carry-chain pass, just above, ended up with a carry from
|
|
+ * input[9], and that caused input[0] to be out-of-bounds, then input[0] was
|
|
+ * < 2^26 + 2*19, because the carry was, at most, two.
|
|
+ *
|
|
+ * If the second pass carried from input[9] again then input[0] is < 2*19 and
|
|
+ * the input[9] -> input[0] carry didn't push input[0] out of bounds. */
|
|
+
|
|
+ /* It still remains the case that input might be between 2^255-19 and 2^255.
|
|
+ * In this case, input[1..9] must take their maximum value and input[0] must
|
|
+ * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */
|
|
+ mask = s32_gte(input[0], 0x3ffffed);
|
|
+ for (i = 1; i < 10; i++) {
|
|
+ if ((i & 1) == 1) {
|
|
+ mask &= s32_eq(input[i], 0x1ffffff);
|
|
+ } else {
|
|
+ mask &= s32_eq(input[i], 0x3ffffff);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus
|
|
+ * this conditionally subtracts 2^255-19. */
|
|
+ input[0] -= mask & 0x3ffffed;
|
|
+
|
|
+ for (i = 1; i < 10; i++) {
|
|
+ if ((i & 1) == 1) {
|
|
+ input[i] -= mask & 0x1ffffff;
|
|
+ } else {
|
|
+ input[i] -= mask & 0x3ffffff;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ input[1] <<= 2;
|
|
+ input[2] <<= 3;
|
|
+ input[3] <<= 5;
|
|
+ input[4] <<= 6;
|
|
+ input[6] <<= 1;
|
|
+ input[7] <<= 3;
|
|
+ input[8] <<= 4;
|
|
+ input[9] <<= 6;
|
|
+#define F(i, s) \
|
|
+ output[s+0] |= input[i] & 0xff; \
|
|
+ output[s+1] = (input[i] >> 8) & 0xff; \
|
|
+ output[s+2] = (input[i] >> 16) & 0xff; \
|
|
+ output[s+3] = (input[i] >> 24) & 0xff;
|
|
+ output[0] = 0;
|
|
+ output[16] = 0;
|
|
+ F(0,0);
|
|
+ F(1,3);
|
|
+ F(2,6);
|
|
+ F(3,9);
|
|
+ F(4,12);
|
|
+ F(5,16);
|
|
+ F(6,19);
|
|
+ F(7,22);
|
|
+ F(8,25);
|
|
+ F(9,28);
|
|
+#undef F
|
|
+}
|
|
+
|
|
+/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
|
|
+ * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
|
|
+ * side-channel attacks.
|
|
+ *
|
|
+ * NOTE that this function requires that 'iswap' be 1 or 0; other values give
|
|
+ * wrong results. Also, the two limb arrays must be in reduced-coefficient,
|
|
+ * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
|
|
+ * and all all values in a[0..9],b[0..9] must have magnitude less than
|
|
+ * INT32_MAX. */
|
|
+static void swap_conditional(limb a[19], limb b[19], limb iswap)
|
|
+{
|
|
+ unsigned i;
|
|
+ const s32 swap = (s32) -iswap;
|
|
+
|
|
+ for (i = 0; i < 10; ++i) {
|
|
+ const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
|
|
+ a[i] = ((s32)a[i]) ^ x;
|
|
+ b[i] = ((s32)b[i]) ^ x;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void crecip(limb *out, const limb *z)
|
|
+{
|
|
+ limb z2[10];
|
|
+ limb z9[10];
|
|
+ limb z11[10];
|
|
+ limb z2_5_0[10];
|
|
+ limb z2_10_0[10];
|
|
+ limb z2_20_0[10];
|
|
+ limb z2_50_0[10];
|
|
+ limb z2_100_0[10];
|
|
+ limb t0[10];
|
|
+ limb t1[10];
|
|
+ int i;
|
|
+
|
|
+ /* 2 */ fsquare(z2,z);
|
|
+ /* 4 */ fsquare(t1,z2);
|
|
+ /* 8 */ fsquare(t0,t1);
|
|
+ /* 9 */ fmul(z9,t0,z);
|
|
+ /* 11 */ fmul(z11,z9,z2);
|
|
+ /* 22 */ fsquare(t0,z11);
|
|
+ /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
|
|
+
|
|
+ /* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
|
|
+ /* 2^7 - 2^2 */ fsquare(t1,t0);
|
|
+ /* 2^8 - 2^3 */ fsquare(t0,t1);
|
|
+ /* 2^9 - 2^4 */ fsquare(t1,t0);
|
|
+ /* 2^10 - 2^5 */ fsquare(t0,t1);
|
|
+ /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
|
|
+
|
|
+ /* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
|
|
+ /* 2^12 - 2^2 */ fsquare(t1,t0);
|
|
+ /* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
|
+ /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
|
|
+
|
|
+ /* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
|
|
+ /* 2^22 - 2^2 */ fsquare(t1,t0);
|
|
+ /* 2^40 - 2^20 */ for (i = 2; i < 20; i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
|
+ /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
|
|
+
|
|
+ /* 2^41 - 2^1 */ fsquare(t1,t0);
|
|
+ /* 2^42 - 2^2 */ fsquare(t0,t1);
|
|
+ /* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
|
+ /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
|
|
+
|
|
+ /* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
|
|
+ /* 2^52 - 2^2 */ fsquare(t1,t0);
|
|
+ /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
|
+ /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
|
|
+
|
|
+ /* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
|
|
+ /* 2^102 - 2^2 */ fsquare(t0,t1);
|
|
+ /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
|
+ /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
|
|
+
|
|
+ /* 2^201 - 2^1 */ fsquare(t0,t1);
|
|
+ /* 2^202 - 2^2 */ fsquare(t1,t0);
|
|
+ /* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
|
+ /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
|
|
+
|
|
+ /* 2^251 - 2^1 */ fsquare(t1,t0);
|
|
+ /* 2^252 - 2^2 */ fsquare(t0,t1);
|
|
+ /* 2^253 - 2^3 */ fsquare(t1,t0);
|
|
+ /* 2^254 - 2^4 */ fsquare(t0,t1);
|
|
+ /* 2^255 - 2^5 */ fsquare(t1,t0);
|
|
+ /* 2^255 - 21 */ fmul(out,t1,z11);
|
|
+}
|
|
+
|
|
+
|
|
+/* Input: Q, Q', Q-Q'
|
|
+ * Output: 2Q, Q+Q'
|
|
+ *
|
|
+ * x2 z3: long form
|
|
+ * x3 z3: long form
|
|
+ * x z: short form, destroyed
|
|
+ * xprime zprime: short form, destroyed
|
|
+ * qmqp: short form, preserved
|
|
+ *
|
|
+ * On entry and exit, the absolute value of the limbs of all inputs and outputs
|
|
+ * are < 2^26. */
|
|
+static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
|
+ limb *x3, limb *z3, /* output Q + Q' */
|
|
+ limb *x, limb *z, /* input Q */
|
|
+ limb *xprime, limb *zprime, /* input Q' */
|
|
+ const limb *qmqp /* input Q - Q' */)
|
|
+{
|
|
+ limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
|
|
+ zzprime[19], zzzprime[19], xxxprime[19];
|
|
+
|
|
+ memcpy(origx, x, 10 * sizeof(limb));
|
|
+ fsum(x, z);
|
|
+ /* |x[i]| < 2^27 */
|
|
+ fdifference(z, origx); /* does x - z */
|
|
+ /* |z[i]| < 2^27 */
|
|
+
|
|
+ memcpy(origxprime, xprime, sizeof(limb) * 10);
|
|
+ fsum(xprime, zprime);
|
|
+ /* |xprime[i]| < 2^27 */
|
|
+ fdifference(zprime, origxprime);
|
|
+ /* |zprime[i]| < 2^27 */
|
|
+ fproduct(xxprime, xprime, z);
|
|
+ /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be <
|
|
+ * 2^(27+27) and fproduct adds together, at most, 14 of those products.
|
|
+ * (Approximating that to 2^58 doesn't work out.) */
|
|
+ fproduct(zzprime, x, zprime);
|
|
+ /* |zzprime[i]| < 14*2^54 */
|
|
+ freduce_degree(xxprime);
|
|
+ freduce_coefficients(xxprime);
|
|
+ /* |xxprime[i]| < 2^26 */
|
|
+ freduce_degree(zzprime);
|
|
+ freduce_coefficients(zzprime);
|
|
+ /* |zzprime[i]| < 2^26 */
|
|
+ memcpy(origxprime, xxprime, sizeof(limb) * 10);
|
|
+ fsum(xxprime, zzprime);
|
|
+ /* |xxprime[i]| < 2^27 */
|
|
+ fdifference(zzprime, origxprime);
|
|
+ /* |zzprime[i]| < 2^27 */
|
|
+ fsquare(xxxprime, xxprime);
|
|
+ /* |xxxprime[i]| < 2^26 */
|
|
+ fsquare(zzzprime, zzprime);
|
|
+ /* |zzzprime[i]| < 2^26 */
|
|
+ fproduct(zzprime, zzzprime, qmqp);
|
|
+ /* |zzprime[i]| < 14*2^52 */
|
|
+ freduce_degree(zzprime);
|
|
+ freduce_coefficients(zzprime);
|
|
+ /* |zzprime[i]| < 2^26 */
|
|
+ memcpy(x3, xxxprime, sizeof(limb) * 10);
|
|
+ memcpy(z3, zzprime, sizeof(limb) * 10);
|
|
+
|
|
+ fsquare(xx, x);
|
|
+ /* |xx[i]| < 2^26 */
|
|
+ fsquare(zz, z);
|
|
+ /* |zz[i]| < 2^26 */
|
|
+ fproduct(x2, xx, zz);
|
|
+ /* |x2[i]| < 14*2^52 */
|
|
+ freduce_degree(x2);
|
|
+ freduce_coefficients(x2);
|
|
+ /* |x2[i]| < 2^26 */
|
|
+ fdifference(zz, xx); // does zz = xx - zz
|
|
+ /* |zz[i]| < 2^27 */
|
|
+ memset(zzz + 10, 0, sizeof(limb) * 9);
|
|
+ fscalar_product(zzz, zz, 121665);
|
|
+ /* |zzz[i]| < 2^(27+17) */
|
|
+ /* No need to call freduce_degree here:
|
|
+ fscalar_product doesn't increase the degree of its input. */
|
|
+ freduce_coefficients(zzz);
|
|
+ /* |zzz[i]| < 2^26 */
|
|
+ fsum(zzz, xx);
|
|
+ /* |zzz[i]| < 2^27 */
|
|
+ fproduct(z2, zz, zzz);
|
|
+ /* |z2[i]| < 14*2^(26+27) */
|
|
+ freduce_degree(z2);
|
|
+ freduce_coefficients(z2);
|
|
+ /* |z2|i| < 2^26 */
|
|
+}
|
|
+
|
|
+/* Calculates nQ where Q is the x-coordinate of a point on the curve
|
|
+ *
|
|
+ * resultx/resultz: the x coordinate of the resulting curve point (short form)
|
|
+ * n: a little endian, 32-byte number
|
|
+ * q: a point of the curve (short form) */
|
|
+static void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q)
|
|
+{
|
|
+ limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
|
|
+ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
|
|
+ limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
|
|
+ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
|
|
+
|
|
+ unsigned i, j;
|
|
+
|
|
+ memcpy(nqpqx, q, sizeof(limb) * 10);
|
|
+
|
|
+ for (i = 0; i < 32; ++i) {
|
|
+ u8 byte = n[31 - i];
|
|
+ for (j = 0; j < 8; ++j) {
|
|
+ const limb bit = byte >> 7;
|
|
+
|
|
+ swap_conditional(nqx, nqpqx, bit);
|
|
+ swap_conditional(nqz, nqpqz, bit);
|
|
+ fmonty(nqx2, nqz2,
|
|
+ nqpqx2, nqpqz2,
|
|
+ nqx, nqz,
|
|
+ nqpqx, nqpqz,
|
|
+ q);
|
|
+ swap_conditional(nqx2, nqpqx2, bit);
|
|
+ swap_conditional(nqz2, nqpqz2, bit);
|
|
+
|
|
+ t = nqx;
|
|
+ nqx = nqx2;
|
|
+ nqx2 = t;
|
|
+ t = nqz;
|
|
+ nqz = nqz2;
|
|
+ nqz2 = t;
|
|
+ t = nqpqx;
|
|
+ nqpqx = nqpqx2;
|
|
+ nqpqx2 = t;
|
|
+ t = nqpqz;
|
|
+ nqpqz = nqpqz2;
|
|
+ nqpqz2 = t;
|
|
+
|
|
+ byte <<= 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ memcpy(resultx, nqx, sizeof(limb) * 10);
|
|
+ memcpy(resultz, nqz, sizeof(limb) * 10);
|
|
+}
|
|
+
|
|
+void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE])
|
|
+{
|
|
+ limb bp[10], x[10], z[11], zmone[10];
|
|
+ u8 e[32];
|
|
+
|
|
+ memcpy(e, secret, 32);
|
|
+ normalize_secret(e);
|
|
+
|
|
+ fexpand(bp, basepoint);
|
|
+ cmult(x, z, e, bp);
|
|
+ crecip(zmone, z);
|
|
+ fmul(z, x, zmone);
|
|
+ fcontract(mypublic, z);
|
|
+
|
|
+ memzero_explicit(e, sizeof(e));
|
|
+ memzero_explicit(bp, sizeof(bp));
|
|
+ memzero_explicit(x, sizeof(x));
|
|
+ memzero_explicit(z, sizeof(z));
|
|
+ memzero_explicit(zmone, sizeof(zmone));
|
|
+}
|
|
+#endif
|
|
+
|
|
+void curve25519_generate_secret(u8 secret[CURVE25519_POINT_SIZE])
|
|
+{
|
|
+ get_random_bytes(secret, CURVE25519_POINT_SIZE);
|
|
+ normalize_secret(secret);
|
|
+}
|
|
+
|
|
+void curve25519_generate_public(u8 pub[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE])
|
|
+{
|
|
+ static const u8 basepoint[CURVE25519_POINT_SIZE] = { 9 };
|
|
+ curve25519(pub, secret, basepoint);
|
|
+}
|
|
+
|
|
+#include "../selftest/curve25519.h"
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/blake2s.h
|
|
@@ -0,0 +1,36 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef BLAKE2S_H
|
|
+#define BLAKE2S_H
|
|
+
|
|
+#include <linux/types.h>
|
|
+
|
|
+enum blake2s_lengths {
|
|
+ BLAKE2S_BLOCKBYTES = 64,
|
|
+ BLAKE2S_OUTBYTES = 32,
|
|
+ BLAKE2S_KEYBYTES = 32
|
|
+};
|
|
+
|
|
+struct blake2s_state {
|
|
+ u32 h[8];
|
|
+ u32 t[2];
|
|
+ u32 f[2];
|
|
+ u8 buf[2 * BLAKE2S_BLOCKBYTES];
|
|
+ size_t buflen;
|
|
+ u8 last_node;
|
|
+};
|
|
+
|
|
+void blake2s(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u8 keylen);
|
|
+
|
|
+void blake2s_init(struct blake2s_state *state, const u8 outlen);
|
|
+void blake2s_init_key(struct blake2s_state *state, const u8 outlen, const void *key, const u8 keylen);
|
|
+void blake2s_update(struct blake2s_state *state, const u8 *in, u64 inlen);
|
|
+void blake2s_final(struct blake2s_state *state, u8 *out, u8 outlen);
|
|
+
|
|
+void blake2s_hmac(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u64 keylen);
|
|
+
|
|
+#ifdef DEBUG
|
|
+bool blake2s_selftest(void);
|
|
+#endif
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/chacha20poly1305.h
|
|
@@ -0,0 +1,78 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef CHACHA20POLY1305_H
|
|
+#define CHACHA20POLY1305_H
|
|
+
|
|
+#include <linux/types.h>
|
|
+
|
|
+struct scatterlist;
|
|
+
|
|
+enum chacha20poly1305_lengths {
|
|
+ XCHACHA20POLY1305_NONCELEN = 24,
|
|
+ CHACHA20POLY1305_KEYLEN = 32,
|
|
+ CHACHA20POLY1305_AUTHTAGLEN = 16
|
|
+};
|
|
+
|
|
+void chacha20poly1305_init(void);
|
|
+
|
|
+bool chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
|
|
+ const u8 *ad, const size_t ad_len,
|
|
+ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]);
|
|
+
|
|
+bool chacha20poly1305_encrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len,
|
|
+ const u8 *ad, const size_t ad_len,
|
|
+ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN],
|
|
+ bool have_simd);
|
|
+
|
|
+bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
|
|
+ const u8 *ad, const size_t ad_len,
|
|
+ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]);
|
|
+
|
|
+bool chacha20poly1305_decrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len,
|
|
+ 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)
|
|
+#include <asm/fpu/api.h>
|
|
+#include <asm/simd.h>
|
|
+#else
|
|
+#include <asm/i387.h>
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+static inline bool chacha20poly1305_init_simd(void)
|
|
+{
|
|
+ bool have_simd = false;
|
|
+#ifdef CONFIG_X86_64
|
|
+ have_simd = irq_fpu_usable();
|
|
+ if (have_simd)
|
|
+ kernel_fpu_begin();
|
|
+#endif
|
|
+ return have_simd;
|
|
+}
|
|
+
|
|
+static inline void chacha20poly1305_deinit_simd(bool was_on)
|
|
+{
|
|
+#ifdef CONFIG_X86_64
|
|
+ if (was_on)
|
|
+ kernel_fpu_end();
|
|
+#endif
|
|
+}
|
|
+
|
|
+#ifdef DEBUG
|
|
+bool chacha20poly1305_selftest(void);
|
|
+#endif
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/curve25519.h
|
|
@@ -0,0 +1,20 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef CURVE25519_H
|
|
+#define CURVE25519_H
|
|
+
|
|
+#include <linux/types.h>
|
|
+
|
|
+enum curve25519_lengths {
|
|
+ CURVE25519_POINT_SIZE = 32
|
|
+};
|
|
+
|
|
+void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE]);
|
|
+void curve25519_generate_secret(u8 secret[CURVE25519_POINT_SIZE]);
|
|
+void curve25519_generate_public(u8 pub[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE]);
|
|
+
|
|
+#ifdef DEBUG
|
|
+bool curve25519_selftest(void);
|
|
+#endif
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/chacha20-avx2-x86_64.S
|
|
@@ -0,0 +1,443 @@
|
|
+/*
|
|
+ * ChaCha20 256-bit cipher algorithm, RFC7539, x64 AVX2 functions
|
|
+ *
|
|
+ * Copyright (C) 2015 Martin Willi
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <linux/linkage.h>
|
|
+
|
|
+.data
|
|
+.align 32
|
|
+
|
|
+ROT8: .octa 0x0e0d0c0f0a09080b0605040702010003
|
|
+ .octa 0x0e0d0c0f0a09080b0605040702010003
|
|
+ROT16: .octa 0x0d0c0f0e09080b0a0504070601000302
|
|
+ .octa 0x0d0c0f0e09080b0a0504070601000302
|
|
+CTRINC: .octa 0x00000003000000020000000100000000
|
|
+ .octa 0x00000007000000060000000500000004
|
|
+
|
|
+.text
|
|
+
|
|
+ENTRY(chacha20_asm_8block_xor_avx2)
|
|
+ # %rdi: Input state matrix, s
|
|
+ # %rsi: 8 data blocks output, o
|
|
+ # %rdx: 8 data blocks input, i
|
|
+
|
|
+ # This function encrypts eight consecutive ChaCha20 blocks by loading
|
|
+ # the state matrix in AVX registers eight times. As we need some
|
|
+ # scratch registers, we save the first four registers on the stack. The
|
|
+ # algorithm performs each operation on the corresponding word of each
|
|
+ # state matrix, hence requires no word shuffling. For final XORing step
|
|
+ # we transpose the matrix by interleaving 32-, 64- and then 128-bit
|
|
+ # words, which allows us to do XOR in AVX registers. 8/16-bit word
|
|
+ # rotation is done with the slightly better performing byte shuffling,
|
|
+ # 7/12-bit word rotation uses traditional shift+OR.
|
|
+
|
|
+ vzeroupper
|
|
+ # 4 * 32 byte stack, 32-byte aligned
|
|
+ mov %rsp, %r8
|
|
+ and $~31, %rsp
|
|
+ sub $0x80, %rsp
|
|
+
|
|
+ # x0..15[0-7] = s[0..15]
|
|
+ vpbroadcastd 0x00(%rdi),%ymm0
|
|
+ vpbroadcastd 0x04(%rdi),%ymm1
|
|
+ vpbroadcastd 0x08(%rdi),%ymm2
|
|
+ vpbroadcastd 0x0c(%rdi),%ymm3
|
|
+ vpbroadcastd 0x10(%rdi),%ymm4
|
|
+ vpbroadcastd 0x14(%rdi),%ymm5
|
|
+ vpbroadcastd 0x18(%rdi),%ymm6
|
|
+ vpbroadcastd 0x1c(%rdi),%ymm7
|
|
+ vpbroadcastd 0x20(%rdi),%ymm8
|
|
+ vpbroadcastd 0x24(%rdi),%ymm9
|
|
+ vpbroadcastd 0x28(%rdi),%ymm10
|
|
+ vpbroadcastd 0x2c(%rdi),%ymm11
|
|
+ vpbroadcastd 0x30(%rdi),%ymm12
|
|
+ vpbroadcastd 0x34(%rdi),%ymm13
|
|
+ vpbroadcastd 0x38(%rdi),%ymm14
|
|
+ vpbroadcastd 0x3c(%rdi),%ymm15
|
|
+ # x0..3 on stack
|
|
+ vmovdqa %ymm0,0x00(%rsp)
|
|
+ vmovdqa %ymm1,0x20(%rsp)
|
|
+ vmovdqa %ymm2,0x40(%rsp)
|
|
+ vmovdqa %ymm3,0x60(%rsp)
|
|
+
|
|
+ vmovdqa CTRINC(%rip),%ymm1
|
|
+ vmovdqa ROT8(%rip),%ymm2
|
|
+ vmovdqa ROT16(%rip),%ymm3
|
|
+
|
|
+ # x12 += counter values 0-3
|
|
+ vpaddd %ymm1,%ymm12,%ymm12
|
|
+
|
|
+ mov $10,%ecx
|
|
+
|
|
+.Ldoubleround8:
|
|
+ # x0 += x4, x12 = rotl32(x12 ^ x0, 16)
|
|
+ vpaddd 0x00(%rsp),%ymm4,%ymm0
|
|
+ vmovdqa %ymm0,0x00(%rsp)
|
|
+ vpxor %ymm0,%ymm12,%ymm12
|
|
+ vpshufb %ymm3,%ymm12,%ymm12
|
|
+ # x1 += x5, x13 = rotl32(x13 ^ x1, 16)
|
|
+ vpaddd 0x20(%rsp),%ymm5,%ymm0
|
|
+ vmovdqa %ymm0,0x20(%rsp)
|
|
+ vpxor %ymm0,%ymm13,%ymm13
|
|
+ vpshufb %ymm3,%ymm13,%ymm13
|
|
+ # x2 += x6, x14 = rotl32(x14 ^ x2, 16)
|
|
+ vpaddd 0x40(%rsp),%ymm6,%ymm0
|
|
+ vmovdqa %ymm0,0x40(%rsp)
|
|
+ vpxor %ymm0,%ymm14,%ymm14
|
|
+ vpshufb %ymm3,%ymm14,%ymm14
|
|
+ # x3 += x7, x15 = rotl32(x15 ^ x3, 16)
|
|
+ vpaddd 0x60(%rsp),%ymm7,%ymm0
|
|
+ vmovdqa %ymm0,0x60(%rsp)
|
|
+ vpxor %ymm0,%ymm15,%ymm15
|
|
+ vpshufb %ymm3,%ymm15,%ymm15
|
|
+
|
|
+ # x8 += x12, x4 = rotl32(x4 ^ x8, 12)
|
|
+ vpaddd %ymm12,%ymm8,%ymm8
|
|
+ vpxor %ymm8,%ymm4,%ymm4
|
|
+ vpslld $12,%ymm4,%ymm0
|
|
+ vpsrld $20,%ymm4,%ymm4
|
|
+ vpor %ymm0,%ymm4,%ymm4
|
|
+ # x9 += x13, x5 = rotl32(x5 ^ x9, 12)
|
|
+ vpaddd %ymm13,%ymm9,%ymm9
|
|
+ vpxor %ymm9,%ymm5,%ymm5
|
|
+ vpslld $12,%ymm5,%ymm0
|
|
+ vpsrld $20,%ymm5,%ymm5
|
|
+ vpor %ymm0,%ymm5,%ymm5
|
|
+ # x10 += x14, x6 = rotl32(x6 ^ x10, 12)
|
|
+ vpaddd %ymm14,%ymm10,%ymm10
|
|
+ vpxor %ymm10,%ymm6,%ymm6
|
|
+ vpslld $12,%ymm6,%ymm0
|
|
+ vpsrld $20,%ymm6,%ymm6
|
|
+ vpor %ymm0,%ymm6,%ymm6
|
|
+ # x11 += x15, x7 = rotl32(x7 ^ x11, 12)
|
|
+ vpaddd %ymm15,%ymm11,%ymm11
|
|
+ vpxor %ymm11,%ymm7,%ymm7
|
|
+ vpslld $12,%ymm7,%ymm0
|
|
+ vpsrld $20,%ymm7,%ymm7
|
|
+ vpor %ymm0,%ymm7,%ymm7
|
|
+
|
|
+ # x0 += x4, x12 = rotl32(x12 ^ x0, 8)
|
|
+ vpaddd 0x00(%rsp),%ymm4,%ymm0
|
|
+ vmovdqa %ymm0,0x00(%rsp)
|
|
+ vpxor %ymm0,%ymm12,%ymm12
|
|
+ vpshufb %ymm2,%ymm12,%ymm12
|
|
+ # x1 += x5, x13 = rotl32(x13 ^ x1, 8)
|
|
+ vpaddd 0x20(%rsp),%ymm5,%ymm0
|
|
+ vmovdqa %ymm0,0x20(%rsp)
|
|
+ vpxor %ymm0,%ymm13,%ymm13
|
|
+ vpshufb %ymm2,%ymm13,%ymm13
|
|
+ # x2 += x6, x14 = rotl32(x14 ^ x2, 8)
|
|
+ vpaddd 0x40(%rsp),%ymm6,%ymm0
|
|
+ vmovdqa %ymm0,0x40(%rsp)
|
|
+ vpxor %ymm0,%ymm14,%ymm14
|
|
+ vpshufb %ymm2,%ymm14,%ymm14
|
|
+ # x3 += x7, x15 = rotl32(x15 ^ x3, 8)
|
|
+ vpaddd 0x60(%rsp),%ymm7,%ymm0
|
|
+ vmovdqa %ymm0,0x60(%rsp)
|
|
+ vpxor %ymm0,%ymm15,%ymm15
|
|
+ vpshufb %ymm2,%ymm15,%ymm15
|
|
+
|
|
+ # x8 += x12, x4 = rotl32(x4 ^ x8, 7)
|
|
+ vpaddd %ymm12,%ymm8,%ymm8
|
|
+ vpxor %ymm8,%ymm4,%ymm4
|
|
+ vpslld $7,%ymm4,%ymm0
|
|
+ vpsrld $25,%ymm4,%ymm4
|
|
+ vpor %ymm0,%ymm4,%ymm4
|
|
+ # x9 += x13, x5 = rotl32(x5 ^ x9, 7)
|
|
+ vpaddd %ymm13,%ymm9,%ymm9
|
|
+ vpxor %ymm9,%ymm5,%ymm5
|
|
+ vpslld $7,%ymm5,%ymm0
|
|
+ vpsrld $25,%ymm5,%ymm5
|
|
+ vpor %ymm0,%ymm5,%ymm5
|
|
+ # x10 += x14, x6 = rotl32(x6 ^ x10, 7)
|
|
+ vpaddd %ymm14,%ymm10,%ymm10
|
|
+ vpxor %ymm10,%ymm6,%ymm6
|
|
+ vpslld $7,%ymm6,%ymm0
|
|
+ vpsrld $25,%ymm6,%ymm6
|
|
+ vpor %ymm0,%ymm6,%ymm6
|
|
+ # x11 += x15, x7 = rotl32(x7 ^ x11, 7)
|
|
+ vpaddd %ymm15,%ymm11,%ymm11
|
|
+ vpxor %ymm11,%ymm7,%ymm7
|
|
+ vpslld $7,%ymm7,%ymm0
|
|
+ vpsrld $25,%ymm7,%ymm7
|
|
+ vpor %ymm0,%ymm7,%ymm7
|
|
+
|
|
+ # x0 += x5, x15 = rotl32(x15 ^ x0, 16)
|
|
+ vpaddd 0x00(%rsp),%ymm5,%ymm0
|
|
+ vmovdqa %ymm0,0x00(%rsp)
|
|
+ vpxor %ymm0,%ymm15,%ymm15
|
|
+ vpshufb %ymm3,%ymm15,%ymm15
|
|
+ # x1 += x6, x12 = rotl32(x12 ^ x1, 16)%ymm0
|
|
+ vpaddd 0x20(%rsp),%ymm6,%ymm0
|
|
+ vmovdqa %ymm0,0x20(%rsp)
|
|
+ vpxor %ymm0,%ymm12,%ymm12
|
|
+ vpshufb %ymm3,%ymm12,%ymm12
|
|
+ # x2 += x7, x13 = rotl32(x13 ^ x2, 16)
|
|
+ vpaddd 0x40(%rsp),%ymm7,%ymm0
|
|
+ vmovdqa %ymm0,0x40(%rsp)
|
|
+ vpxor %ymm0,%ymm13,%ymm13
|
|
+ vpshufb %ymm3,%ymm13,%ymm13
|
|
+ # x3 += x4, x14 = rotl32(x14 ^ x3, 16)
|
|
+ vpaddd 0x60(%rsp),%ymm4,%ymm0
|
|
+ vmovdqa %ymm0,0x60(%rsp)
|
|
+ vpxor %ymm0,%ymm14,%ymm14
|
|
+ vpshufb %ymm3,%ymm14,%ymm14
|
|
+
|
|
+ # x10 += x15, x5 = rotl32(x5 ^ x10, 12)
|
|
+ vpaddd %ymm15,%ymm10,%ymm10
|
|
+ vpxor %ymm10,%ymm5,%ymm5
|
|
+ vpslld $12,%ymm5,%ymm0
|
|
+ vpsrld $20,%ymm5,%ymm5
|
|
+ vpor %ymm0,%ymm5,%ymm5
|
|
+ # x11 += x12, x6 = rotl32(x6 ^ x11, 12)
|
|
+ vpaddd %ymm12,%ymm11,%ymm11
|
|
+ vpxor %ymm11,%ymm6,%ymm6
|
|
+ vpslld $12,%ymm6,%ymm0
|
|
+ vpsrld $20,%ymm6,%ymm6
|
|
+ vpor %ymm0,%ymm6,%ymm6
|
|
+ # x8 += x13, x7 = rotl32(x7 ^ x8, 12)
|
|
+ vpaddd %ymm13,%ymm8,%ymm8
|
|
+ vpxor %ymm8,%ymm7,%ymm7
|
|
+ vpslld $12,%ymm7,%ymm0
|
|
+ vpsrld $20,%ymm7,%ymm7
|
|
+ vpor %ymm0,%ymm7,%ymm7
|
|
+ # x9 += x14, x4 = rotl32(x4 ^ x9, 12)
|
|
+ vpaddd %ymm14,%ymm9,%ymm9
|
|
+ vpxor %ymm9,%ymm4,%ymm4
|
|
+ vpslld $12,%ymm4,%ymm0
|
|
+ vpsrld $20,%ymm4,%ymm4
|
|
+ vpor %ymm0,%ymm4,%ymm4
|
|
+
|
|
+ # x0 += x5, x15 = rotl32(x15 ^ x0, 8)
|
|
+ vpaddd 0x00(%rsp),%ymm5,%ymm0
|
|
+ vmovdqa %ymm0,0x00(%rsp)
|
|
+ vpxor %ymm0,%ymm15,%ymm15
|
|
+ vpshufb %ymm2,%ymm15,%ymm15
|
|
+ # x1 += x6, x12 = rotl32(x12 ^ x1, 8)
|
|
+ vpaddd 0x20(%rsp),%ymm6,%ymm0
|
|
+ vmovdqa %ymm0,0x20(%rsp)
|
|
+ vpxor %ymm0,%ymm12,%ymm12
|
|
+ vpshufb %ymm2,%ymm12,%ymm12
|
|
+ # x2 += x7, x13 = rotl32(x13 ^ x2, 8)
|
|
+ vpaddd 0x40(%rsp),%ymm7,%ymm0
|
|
+ vmovdqa %ymm0,0x40(%rsp)
|
|
+ vpxor %ymm0,%ymm13,%ymm13
|
|
+ vpshufb %ymm2,%ymm13,%ymm13
|
|
+ # x3 += x4, x14 = rotl32(x14 ^ x3, 8)
|
|
+ vpaddd 0x60(%rsp),%ymm4,%ymm0
|
|
+ vmovdqa %ymm0,0x60(%rsp)
|
|
+ vpxor %ymm0,%ymm14,%ymm14
|
|
+ vpshufb %ymm2,%ymm14,%ymm14
|
|
+
|
|
+ # x10 += x15, x5 = rotl32(x5 ^ x10, 7)
|
|
+ vpaddd %ymm15,%ymm10,%ymm10
|
|
+ vpxor %ymm10,%ymm5,%ymm5
|
|
+ vpslld $7,%ymm5,%ymm0
|
|
+ vpsrld $25,%ymm5,%ymm5
|
|
+ vpor %ymm0,%ymm5,%ymm5
|
|
+ # x11 += x12, x6 = rotl32(x6 ^ x11, 7)
|
|
+ vpaddd %ymm12,%ymm11,%ymm11
|
|
+ vpxor %ymm11,%ymm6,%ymm6
|
|
+ vpslld $7,%ymm6,%ymm0
|
|
+ vpsrld $25,%ymm6,%ymm6
|
|
+ vpor %ymm0,%ymm6,%ymm6
|
|
+ # x8 += x13, x7 = rotl32(x7 ^ x8, 7)
|
|
+ vpaddd %ymm13,%ymm8,%ymm8
|
|
+ vpxor %ymm8,%ymm7,%ymm7
|
|
+ vpslld $7,%ymm7,%ymm0
|
|
+ vpsrld $25,%ymm7,%ymm7
|
|
+ vpor %ymm0,%ymm7,%ymm7
|
|
+ # x9 += x14, x4 = rotl32(x4 ^ x9, 7)
|
|
+ vpaddd %ymm14,%ymm9,%ymm9
|
|
+ vpxor %ymm9,%ymm4,%ymm4
|
|
+ vpslld $7,%ymm4,%ymm0
|
|
+ vpsrld $25,%ymm4,%ymm4
|
|
+ vpor %ymm0,%ymm4,%ymm4
|
|
+
|
|
+ dec %ecx
|
|
+ jnz .Ldoubleround8
|
|
+
|
|
+ # x0..15[0-3] += s[0..15]
|
|
+ vpbroadcastd 0x00(%rdi),%ymm0
|
|
+ vpaddd 0x00(%rsp),%ymm0,%ymm0
|
|
+ vmovdqa %ymm0,0x00(%rsp)
|
|
+ vpbroadcastd 0x04(%rdi),%ymm0
|
|
+ vpaddd 0x20(%rsp),%ymm0,%ymm0
|
|
+ vmovdqa %ymm0,0x20(%rsp)
|
|
+ vpbroadcastd 0x08(%rdi),%ymm0
|
|
+ vpaddd 0x40(%rsp),%ymm0,%ymm0
|
|
+ vmovdqa %ymm0,0x40(%rsp)
|
|
+ vpbroadcastd 0x0c(%rdi),%ymm0
|
|
+ vpaddd 0x60(%rsp),%ymm0,%ymm0
|
|
+ vmovdqa %ymm0,0x60(%rsp)
|
|
+ vpbroadcastd 0x10(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm4,%ymm4
|
|
+ vpbroadcastd 0x14(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm5,%ymm5
|
|
+ vpbroadcastd 0x18(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm6,%ymm6
|
|
+ vpbroadcastd 0x1c(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm7,%ymm7
|
|
+ vpbroadcastd 0x20(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm8,%ymm8
|
|
+ vpbroadcastd 0x24(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm9,%ymm9
|
|
+ vpbroadcastd 0x28(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm10,%ymm10
|
|
+ vpbroadcastd 0x2c(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm11,%ymm11
|
|
+ vpbroadcastd 0x30(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm12,%ymm12
|
|
+ vpbroadcastd 0x34(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm13,%ymm13
|
|
+ vpbroadcastd 0x38(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm14,%ymm14
|
|
+ vpbroadcastd 0x3c(%rdi),%ymm0
|
|
+ vpaddd %ymm0,%ymm15,%ymm15
|
|
+
|
|
+ # x12 += counter values 0-3
|
|
+ vpaddd %ymm1,%ymm12,%ymm12
|
|
+
|
|
+ # interleave 32-bit words in state n, n+1
|
|
+ vmovdqa 0x00(%rsp),%ymm0
|
|
+ vmovdqa 0x20(%rsp),%ymm1
|
|
+ vpunpckldq %ymm1,%ymm0,%ymm2
|
|
+ vpunpckhdq %ymm1,%ymm0,%ymm1
|
|
+ vmovdqa %ymm2,0x00(%rsp)
|
|
+ vmovdqa %ymm1,0x20(%rsp)
|
|
+ vmovdqa 0x40(%rsp),%ymm0
|
|
+ vmovdqa 0x60(%rsp),%ymm1
|
|
+ vpunpckldq %ymm1,%ymm0,%ymm2
|
|
+ vpunpckhdq %ymm1,%ymm0,%ymm1
|
|
+ vmovdqa %ymm2,0x40(%rsp)
|
|
+ vmovdqa %ymm1,0x60(%rsp)
|
|
+ vmovdqa %ymm4,%ymm0
|
|
+ vpunpckldq %ymm5,%ymm0,%ymm4
|
|
+ vpunpckhdq %ymm5,%ymm0,%ymm5
|
|
+ vmovdqa %ymm6,%ymm0
|
|
+ vpunpckldq %ymm7,%ymm0,%ymm6
|
|
+ vpunpckhdq %ymm7,%ymm0,%ymm7
|
|
+ vmovdqa %ymm8,%ymm0
|
|
+ vpunpckldq %ymm9,%ymm0,%ymm8
|
|
+ vpunpckhdq %ymm9,%ymm0,%ymm9
|
|
+ vmovdqa %ymm10,%ymm0
|
|
+ vpunpckldq %ymm11,%ymm0,%ymm10
|
|
+ vpunpckhdq %ymm11,%ymm0,%ymm11
|
|
+ vmovdqa %ymm12,%ymm0
|
|
+ vpunpckldq %ymm13,%ymm0,%ymm12
|
|
+ vpunpckhdq %ymm13,%ymm0,%ymm13
|
|
+ vmovdqa %ymm14,%ymm0
|
|
+ vpunpckldq %ymm15,%ymm0,%ymm14
|
|
+ vpunpckhdq %ymm15,%ymm0,%ymm15
|
|
+
|
|
+ # interleave 64-bit words in state n, n+2
|
|
+ vmovdqa 0x00(%rsp),%ymm0
|
|
+ vmovdqa 0x40(%rsp),%ymm2
|
|
+ vpunpcklqdq %ymm2,%ymm0,%ymm1
|
|
+ vpunpckhqdq %ymm2,%ymm0,%ymm2
|
|
+ vmovdqa %ymm1,0x00(%rsp)
|
|
+ vmovdqa %ymm2,0x40(%rsp)
|
|
+ vmovdqa 0x20(%rsp),%ymm0
|
|
+ vmovdqa 0x60(%rsp),%ymm2
|
|
+ vpunpcklqdq %ymm2,%ymm0,%ymm1
|
|
+ vpunpckhqdq %ymm2,%ymm0,%ymm2
|
|
+ vmovdqa %ymm1,0x20(%rsp)
|
|
+ vmovdqa %ymm2,0x60(%rsp)
|
|
+ vmovdqa %ymm4,%ymm0
|
|
+ vpunpcklqdq %ymm6,%ymm0,%ymm4
|
|
+ vpunpckhqdq %ymm6,%ymm0,%ymm6
|
|
+ vmovdqa %ymm5,%ymm0
|
|
+ vpunpcklqdq %ymm7,%ymm0,%ymm5
|
|
+ vpunpckhqdq %ymm7,%ymm0,%ymm7
|
|
+ vmovdqa %ymm8,%ymm0
|
|
+ vpunpcklqdq %ymm10,%ymm0,%ymm8
|
|
+ vpunpckhqdq %ymm10,%ymm0,%ymm10
|
|
+ vmovdqa %ymm9,%ymm0
|
|
+ vpunpcklqdq %ymm11,%ymm0,%ymm9
|
|
+ vpunpckhqdq %ymm11,%ymm0,%ymm11
|
|
+ vmovdqa %ymm12,%ymm0
|
|
+ vpunpcklqdq %ymm14,%ymm0,%ymm12
|
|
+ vpunpckhqdq %ymm14,%ymm0,%ymm14
|
|
+ vmovdqa %ymm13,%ymm0
|
|
+ vpunpcklqdq %ymm15,%ymm0,%ymm13
|
|
+ vpunpckhqdq %ymm15,%ymm0,%ymm15
|
|
+
|
|
+ # interleave 128-bit words in state n, n+4
|
|
+ vmovdqa 0x00(%rsp),%ymm0
|
|
+ vperm2i128 $0x20,%ymm4,%ymm0,%ymm1
|
|
+ vperm2i128 $0x31,%ymm4,%ymm0,%ymm4
|
|
+ vmovdqa %ymm1,0x00(%rsp)
|
|
+ vmovdqa 0x20(%rsp),%ymm0
|
|
+ vperm2i128 $0x20,%ymm5,%ymm0,%ymm1
|
|
+ vperm2i128 $0x31,%ymm5,%ymm0,%ymm5
|
|
+ vmovdqa %ymm1,0x20(%rsp)
|
|
+ vmovdqa 0x40(%rsp),%ymm0
|
|
+ vperm2i128 $0x20,%ymm6,%ymm0,%ymm1
|
|
+ vperm2i128 $0x31,%ymm6,%ymm0,%ymm6
|
|
+ vmovdqa %ymm1,0x40(%rsp)
|
|
+ vmovdqa 0x60(%rsp),%ymm0
|
|
+ vperm2i128 $0x20,%ymm7,%ymm0,%ymm1
|
|
+ vperm2i128 $0x31,%ymm7,%ymm0,%ymm7
|
|
+ vmovdqa %ymm1,0x60(%rsp)
|
|
+ vperm2i128 $0x20,%ymm12,%ymm8,%ymm0
|
|
+ vperm2i128 $0x31,%ymm12,%ymm8,%ymm12
|
|
+ vmovdqa %ymm0,%ymm8
|
|
+ vperm2i128 $0x20,%ymm13,%ymm9,%ymm0
|
|
+ vperm2i128 $0x31,%ymm13,%ymm9,%ymm13
|
|
+ vmovdqa %ymm0,%ymm9
|
|
+ vperm2i128 $0x20,%ymm14,%ymm10,%ymm0
|
|
+ vperm2i128 $0x31,%ymm14,%ymm10,%ymm14
|
|
+ vmovdqa %ymm0,%ymm10
|
|
+ vperm2i128 $0x20,%ymm15,%ymm11,%ymm0
|
|
+ vperm2i128 $0x31,%ymm15,%ymm11,%ymm15
|
|
+ vmovdqa %ymm0,%ymm11
|
|
+
|
|
+ # xor with corresponding input, write to output
|
|
+ vmovdqa 0x00(%rsp),%ymm0
|
|
+ vpxor 0x0000(%rdx),%ymm0,%ymm0
|
|
+ vmovdqu %ymm0,0x0000(%rsi)
|
|
+ vmovdqa 0x20(%rsp),%ymm0
|
|
+ vpxor 0x0080(%rdx),%ymm0,%ymm0
|
|
+ vmovdqu %ymm0,0x0080(%rsi)
|
|
+ vmovdqa 0x40(%rsp),%ymm0
|
|
+ vpxor 0x0040(%rdx),%ymm0,%ymm0
|
|
+ vmovdqu %ymm0,0x0040(%rsi)
|
|
+ vmovdqa 0x60(%rsp),%ymm0
|
|
+ vpxor 0x00c0(%rdx),%ymm0,%ymm0
|
|
+ vmovdqu %ymm0,0x00c0(%rsi)
|
|
+ vpxor 0x0100(%rdx),%ymm4,%ymm4
|
|
+ vmovdqu %ymm4,0x0100(%rsi)
|
|
+ vpxor 0x0180(%rdx),%ymm5,%ymm5
|
|
+ vmovdqu %ymm5,0x00180(%rsi)
|
|
+ vpxor 0x0140(%rdx),%ymm6,%ymm6
|
|
+ vmovdqu %ymm6,0x0140(%rsi)
|
|
+ vpxor 0x01c0(%rdx),%ymm7,%ymm7
|
|
+ vmovdqu %ymm7,0x01c0(%rsi)
|
|
+ vpxor 0x0020(%rdx),%ymm8,%ymm8
|
|
+ vmovdqu %ymm8,0x0020(%rsi)
|
|
+ vpxor 0x00a0(%rdx),%ymm9,%ymm9
|
|
+ vmovdqu %ymm9,0x00a0(%rsi)
|
|
+ vpxor 0x0060(%rdx),%ymm10,%ymm10
|
|
+ vmovdqu %ymm10,0x0060(%rsi)
|
|
+ vpxor 0x00e0(%rdx),%ymm11,%ymm11
|
|
+ vmovdqu %ymm11,0x00e0(%rsi)
|
|
+ vpxor 0x0120(%rdx),%ymm12,%ymm12
|
|
+ vmovdqu %ymm12,0x0120(%rsi)
|
|
+ vpxor 0x01a0(%rdx),%ymm13,%ymm13
|
|
+ vmovdqu %ymm13,0x01a0(%rsi)
|
|
+ vpxor 0x0160(%rdx),%ymm14,%ymm14
|
|
+ vmovdqu %ymm14,0x0160(%rsi)
|
|
+ vpxor 0x01e0(%rdx),%ymm15,%ymm15
|
|
+ vmovdqu %ymm15,0x01e0(%rsi)
|
|
+
|
|
+ vzeroupper
|
|
+ mov %r8,%rsp
|
|
+ ret
|
|
+ENDPROC(chacha20_asm_8block_xor_avx2)
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/chacha20-ssse3-x86_64.S
|
|
@@ -0,0 +1,627 @@
|
|
+/*
|
|
+ * ChaCha20 256-bit cipher algorithm, RFC7539, x64 SSSE3 functions
|
|
+ *
|
|
+ * Copyright (C) 2015 Martin Willi
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <linux/linkage.h>
|
|
+
|
|
+.data
|
|
+.align 16
|
|
+
|
|
+ROT8: .octa 0x0e0d0c0f0a09080b0605040702010003
|
|
+ROT16: .octa 0x0d0c0f0e09080b0a0504070601000302
|
|
+CTRINC: .octa 0x00000003000000020000000100000000
|
|
+
|
|
+.text
|
|
+
|
|
+ENTRY(chacha20_asm_block_xor_ssse3)
|
|
+ # %rdi: Input state matrix, s
|
|
+ # %rsi: 1 data block output, o
|
|
+ # %rdx: 1 data block input, i
|
|
+
|
|
+ # This function encrypts one ChaCha20 block by loading the state matrix
|
|
+ # in four SSE registers. It performs matrix operation on four words in
|
|
+ # parallel, but requireds shuffling to rearrange the words after each
|
|
+ # round. 8/16-bit word rotation is done with the slightly better
|
|
+ # performing SSSE3 byte shuffling, 7/12-bit word rotation uses
|
|
+ # traditional shift+OR.
|
|
+
|
|
+ # x0..3 = s0..3
|
|
+ movdqa 0x00(%rdi),%xmm0
|
|
+ movdqa 0x10(%rdi),%xmm1
|
|
+ movdqa 0x20(%rdi),%xmm2
|
|
+ movdqa 0x30(%rdi),%xmm3
|
|
+ movdqa %xmm0,%xmm8
|
|
+ movdqa %xmm1,%xmm9
|
|
+ movdqa %xmm2,%xmm10
|
|
+ movdqa %xmm3,%xmm11
|
|
+
|
|
+ movdqa ROT8(%rip),%xmm4
|
|
+ movdqa ROT16(%rip),%xmm5
|
|
+
|
|
+ mov $10,%ecx
|
|
+
|
|
+.Ldoubleround:
|
|
+
|
|
+ # x0 += x1, x3 = rotl32(x3 ^ x0, 16)
|
|
+ paddd %xmm1,%xmm0
|
|
+ pxor %xmm0,%xmm3
|
|
+ pshufb %xmm5,%xmm3
|
|
+
|
|
+ # x2 += x3, x1 = rotl32(x1 ^ x2, 12)
|
|
+ paddd %xmm3,%xmm2
|
|
+ pxor %xmm2,%xmm1
|
|
+ movdqa %xmm1,%xmm6
|
|
+ pslld $12,%xmm6
|
|
+ psrld $20,%xmm1
|
|
+ por %xmm6,%xmm1
|
|
+
|
|
+ # x0 += x1, x3 = rotl32(x3 ^ x0, 8)
|
|
+ paddd %xmm1,%xmm0
|
|
+ pxor %xmm0,%xmm3
|
|
+ pshufb %xmm4,%xmm3
|
|
+
|
|
+ # x2 += x3, x1 = rotl32(x1 ^ x2, 7)
|
|
+ paddd %xmm3,%xmm2
|
|
+ pxor %xmm2,%xmm1
|
|
+ movdqa %xmm1,%xmm7
|
|
+ pslld $7,%xmm7
|
|
+ psrld $25,%xmm1
|
|
+ por %xmm7,%xmm1
|
|
+
|
|
+ # x1 = shuffle32(x1, MASK(0, 3, 2, 1))
|
|
+ pshufd $0x39,%xmm1,%xmm1
|
|
+ # x2 = shuffle32(x2, MASK(1, 0, 3, 2))
|
|
+ pshufd $0x4e,%xmm2,%xmm2
|
|
+ # x3 = shuffle32(x3, MASK(2, 1, 0, 3))
|
|
+ pshufd $0x93,%xmm3,%xmm3
|
|
+
|
|
+ # x0 += x1, x3 = rotl32(x3 ^ x0, 16)
|
|
+ paddd %xmm1,%xmm0
|
|
+ pxor %xmm0,%xmm3
|
|
+ pshufb %xmm5,%xmm3
|
|
+
|
|
+ # x2 += x3, x1 = rotl32(x1 ^ x2, 12)
|
|
+ paddd %xmm3,%xmm2
|
|
+ pxor %xmm2,%xmm1
|
|
+ movdqa %xmm1,%xmm6
|
|
+ pslld $12,%xmm6
|
|
+ psrld $20,%xmm1
|
|
+ por %xmm6,%xmm1
|
|
+
|
|
+ # x0 += x1, x3 = rotl32(x3 ^ x0, 8)
|
|
+ paddd %xmm1,%xmm0
|
|
+ pxor %xmm0,%xmm3
|
|
+ pshufb %xmm4,%xmm3
|
|
+
|
|
+ # x2 += x3, x1 = rotl32(x1 ^ x2, 7)
|
|
+ paddd %xmm3,%xmm2
|
|
+ pxor %xmm2,%xmm1
|
|
+ movdqa %xmm1,%xmm7
|
|
+ pslld $7,%xmm7
|
|
+ psrld $25,%xmm1
|
|
+ por %xmm7,%xmm1
|
|
+
|
|
+ # x1 = shuffle32(x1, MASK(2, 1, 0, 3))
|
|
+ pshufd $0x93,%xmm1,%xmm1
|
|
+ # x2 = shuffle32(x2, MASK(1, 0, 3, 2))
|
|
+ pshufd $0x4e,%xmm2,%xmm2
|
|
+ # x3 = shuffle32(x3, MASK(0, 3, 2, 1))
|
|
+ pshufd $0x39,%xmm3,%xmm3
|
|
+
|
|
+ dec %ecx
|
|
+ jnz .Ldoubleround
|
|
+
|
|
+ # o0 = i0 ^ (x0 + s0)
|
|
+ movdqu 0x00(%rdx),%xmm4
|
|
+ paddd %xmm8,%xmm0
|
|
+ pxor %xmm4,%xmm0
|
|
+ movdqu %xmm0,0x00(%rsi)
|
|
+ # o1 = i1 ^ (x1 + s1)
|
|
+ movdqu 0x10(%rdx),%xmm5
|
|
+ paddd %xmm9,%xmm1
|
|
+ pxor %xmm5,%xmm1
|
|
+ movdqu %xmm1,0x10(%rsi)
|
|
+ # o2 = i2 ^ (x2 + s2)
|
|
+ movdqu 0x20(%rdx),%xmm6
|
|
+ paddd %xmm10,%xmm2
|
|
+ pxor %xmm6,%xmm2
|
|
+ movdqu %xmm2,0x20(%rsi)
|
|
+ # o3 = i3 ^ (x3 + s3)
|
|
+ movdqu 0x30(%rdx),%xmm7
|
|
+ paddd %xmm11,%xmm3
|
|
+ pxor %xmm7,%xmm3
|
|
+ movdqu %xmm3,0x30(%rsi)
|
|
+
|
|
+ ret
|
|
+ENDPROC(chacha20_asm_block_xor_ssse3)
|
|
+
|
|
+ENTRY(chacha20_asm_4block_xor_ssse3)
|
|
+ # %rdi: Input state matrix, s
|
|
+ # %rsi: 4 data blocks output, o
|
|
+ # %rdx: 4 data blocks input, i
|
|
+
|
|
+ # This function encrypts four consecutive ChaCha20 blocks by loading the
|
|
+ # the state matrix in SSE registers four times. As we need some scratch
|
|
+ # registers, we save the first four registers on the stack. The
|
|
+ # algorithm performs each operation on the corresponding word of each
|
|
+ # state matrix, hence requires no word shuffling. For final XORing step
|
|
+ # we transpose the matrix by interleaving 32- and then 64-bit words,
|
|
+ # which allows us to do XOR in SSE registers. 8/16-bit word rotation is
|
|
+ # done with the slightly better performing SSSE3 byte shuffling,
|
|
+ # 7/12-bit word rotation uses traditional shift+OR.
|
|
+
|
|
+ mov %rsp,%r11
|
|
+ sub $0x80,%rsp
|
|
+ and $~63,%rsp
|
|
+
|
|
+ # x0..15[0-3] = s0..3[0..3]
|
|
+ movq 0x00(%rdi),%xmm1
|
|
+ pshufd $0x00,%xmm1,%xmm0
|
|
+ pshufd $0x55,%xmm1,%xmm1
|
|
+ movq 0x08(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ movq 0x10(%rdi),%xmm5
|
|
+ pshufd $0x00,%xmm5,%xmm4
|
|
+ pshufd $0x55,%xmm5,%xmm5
|
|
+ movq 0x18(%rdi),%xmm7
|
|
+ pshufd $0x00,%xmm7,%xmm6
|
|
+ pshufd $0x55,%xmm7,%xmm7
|
|
+ movq 0x20(%rdi),%xmm9
|
|
+ pshufd $0x00,%xmm9,%xmm8
|
|
+ pshufd $0x55,%xmm9,%xmm9
|
|
+ movq 0x28(%rdi),%xmm11
|
|
+ pshufd $0x00,%xmm11,%xmm10
|
|
+ pshufd $0x55,%xmm11,%xmm11
|
|
+ movq 0x30(%rdi),%xmm13
|
|
+ pshufd $0x00,%xmm13,%xmm12
|
|
+ pshufd $0x55,%xmm13,%xmm13
|
|
+ movq 0x38(%rdi),%xmm15
|
|
+ pshufd $0x00,%xmm15,%xmm14
|
|
+ pshufd $0x55,%xmm15,%xmm15
|
|
+ # x0..3 on stack
|
|
+ movdqa %xmm0,0x00(%rsp)
|
|
+ movdqa %xmm1,0x10(%rsp)
|
|
+ movdqa %xmm2,0x20(%rsp)
|
|
+ movdqa %xmm3,0x30(%rsp)
|
|
+
|
|
+ movdqa CTRINC(%rip),%xmm1
|
|
+ movdqa ROT8(%rip),%xmm2
|
|
+ movdqa ROT16(%rip),%xmm3
|
|
+
|
|
+ # x12 += counter values 0-3
|
|
+ paddd %xmm1,%xmm12
|
|
+
|
|
+ mov $10,%ecx
|
|
+
|
|
+.Ldoubleround4:
|
|
+ # x0 += x4, x12 = rotl32(x12 ^ x0, 16)
|
|
+ movdqa 0x00(%rsp),%xmm0
|
|
+ paddd %xmm4,%xmm0
|
|
+ movdqa %xmm0,0x00(%rsp)
|
|
+ pxor %xmm0,%xmm12
|
|
+ pshufb %xmm3,%xmm12
|
|
+ # x1 += x5, x13 = rotl32(x13 ^ x1, 16)
|
|
+ movdqa 0x10(%rsp),%xmm0
|
|
+ paddd %xmm5,%xmm0
|
|
+ movdqa %xmm0,0x10(%rsp)
|
|
+ pxor %xmm0,%xmm13
|
|
+ pshufb %xmm3,%xmm13
|
|
+ # x2 += x6, x14 = rotl32(x14 ^ x2, 16)
|
|
+ movdqa 0x20(%rsp),%xmm0
|
|
+ paddd %xmm6,%xmm0
|
|
+ movdqa %xmm0,0x20(%rsp)
|
|
+ pxor %xmm0,%xmm14
|
|
+ pshufb %xmm3,%xmm14
|
|
+ # x3 += x7, x15 = rotl32(x15 ^ x3, 16)
|
|
+ movdqa 0x30(%rsp),%xmm0
|
|
+ paddd %xmm7,%xmm0
|
|
+ movdqa %xmm0,0x30(%rsp)
|
|
+ pxor %xmm0,%xmm15
|
|
+ pshufb %xmm3,%xmm15
|
|
+
|
|
+ # x8 += x12, x4 = rotl32(x4 ^ x8, 12)
|
|
+ paddd %xmm12,%xmm8
|
|
+ pxor %xmm8,%xmm4
|
|
+ movdqa %xmm4,%xmm0
|
|
+ pslld $12,%xmm0
|
|
+ psrld $20,%xmm4
|
|
+ por %xmm0,%xmm4
|
|
+ # x9 += x13, x5 = rotl32(x5 ^ x9, 12)
|
|
+ paddd %xmm13,%xmm9
|
|
+ pxor %xmm9,%xmm5
|
|
+ movdqa %xmm5,%xmm0
|
|
+ pslld $12,%xmm0
|
|
+ psrld $20,%xmm5
|
|
+ por %xmm0,%xmm5
|
|
+ # x10 += x14, x6 = rotl32(x6 ^ x10, 12)
|
|
+ paddd %xmm14,%xmm10
|
|
+ pxor %xmm10,%xmm6
|
|
+ movdqa %xmm6,%xmm0
|
|
+ pslld $12,%xmm0
|
|
+ psrld $20,%xmm6
|
|
+ por %xmm0,%xmm6
|
|
+ # x11 += x15, x7 = rotl32(x7 ^ x11, 12)
|
|
+ paddd %xmm15,%xmm11
|
|
+ pxor %xmm11,%xmm7
|
|
+ movdqa %xmm7,%xmm0
|
|
+ pslld $12,%xmm0
|
|
+ psrld $20,%xmm7
|
|
+ por %xmm0,%xmm7
|
|
+
|
|
+ # x0 += x4, x12 = rotl32(x12 ^ x0, 8)
|
|
+ movdqa 0x00(%rsp),%xmm0
|
|
+ paddd %xmm4,%xmm0
|
|
+ movdqa %xmm0,0x00(%rsp)
|
|
+ pxor %xmm0,%xmm12
|
|
+ pshufb %xmm2,%xmm12
|
|
+ # x1 += x5, x13 = rotl32(x13 ^ x1, 8)
|
|
+ movdqa 0x10(%rsp),%xmm0
|
|
+ paddd %xmm5,%xmm0
|
|
+ movdqa %xmm0,0x10(%rsp)
|
|
+ pxor %xmm0,%xmm13
|
|
+ pshufb %xmm2,%xmm13
|
|
+ # x2 += x6, x14 = rotl32(x14 ^ x2, 8)
|
|
+ movdqa 0x20(%rsp),%xmm0
|
|
+ paddd %xmm6,%xmm0
|
|
+ movdqa %xmm0,0x20(%rsp)
|
|
+ pxor %xmm0,%xmm14
|
|
+ pshufb %xmm2,%xmm14
|
|
+ # x3 += x7, x15 = rotl32(x15 ^ x3, 8)
|
|
+ movdqa 0x30(%rsp),%xmm0
|
|
+ paddd %xmm7,%xmm0
|
|
+ movdqa %xmm0,0x30(%rsp)
|
|
+ pxor %xmm0,%xmm15
|
|
+ pshufb %xmm2,%xmm15
|
|
+
|
|
+ # x8 += x12, x4 = rotl32(x4 ^ x8, 7)
|
|
+ paddd %xmm12,%xmm8
|
|
+ pxor %xmm8,%xmm4
|
|
+ movdqa %xmm4,%xmm0
|
|
+ pslld $7,%xmm0
|
|
+ psrld $25,%xmm4
|
|
+ por %xmm0,%xmm4
|
|
+ # x9 += x13, x5 = rotl32(x5 ^ x9, 7)
|
|
+ paddd %xmm13,%xmm9
|
|
+ pxor %xmm9,%xmm5
|
|
+ movdqa %xmm5,%xmm0
|
|
+ pslld $7,%xmm0
|
|
+ psrld $25,%xmm5
|
|
+ por %xmm0,%xmm5
|
|
+ # x10 += x14, x6 = rotl32(x6 ^ x10, 7)
|
|
+ paddd %xmm14,%xmm10
|
|
+ pxor %xmm10,%xmm6
|
|
+ movdqa %xmm6,%xmm0
|
|
+ pslld $7,%xmm0
|
|
+ psrld $25,%xmm6
|
|
+ por %xmm0,%xmm6
|
|
+ # x11 += x15, x7 = rotl32(x7 ^ x11, 7)
|
|
+ paddd %xmm15,%xmm11
|
|
+ pxor %xmm11,%xmm7
|
|
+ movdqa %xmm7,%xmm0
|
|
+ pslld $7,%xmm0
|
|
+ psrld $25,%xmm7
|
|
+ por %xmm0,%xmm7
|
|
+
|
|
+ # x0 += x5, x15 = rotl32(x15 ^ x0, 16)
|
|
+ movdqa 0x00(%rsp),%xmm0
|
|
+ paddd %xmm5,%xmm0
|
|
+ movdqa %xmm0,0x00(%rsp)
|
|
+ pxor %xmm0,%xmm15
|
|
+ pshufb %xmm3,%xmm15
|
|
+ # x1 += x6, x12 = rotl32(x12 ^ x1, 16)
|
|
+ movdqa 0x10(%rsp),%xmm0
|
|
+ paddd %xmm6,%xmm0
|
|
+ movdqa %xmm0,0x10(%rsp)
|
|
+ pxor %xmm0,%xmm12
|
|
+ pshufb %xmm3,%xmm12
|
|
+ # x2 += x7, x13 = rotl32(x13 ^ x2, 16)
|
|
+ movdqa 0x20(%rsp),%xmm0
|
|
+ paddd %xmm7,%xmm0
|
|
+ movdqa %xmm0,0x20(%rsp)
|
|
+ pxor %xmm0,%xmm13
|
|
+ pshufb %xmm3,%xmm13
|
|
+ # x3 += x4, x14 = rotl32(x14 ^ x3, 16)
|
|
+ movdqa 0x30(%rsp),%xmm0
|
|
+ paddd %xmm4,%xmm0
|
|
+ movdqa %xmm0,0x30(%rsp)
|
|
+ pxor %xmm0,%xmm14
|
|
+ pshufb %xmm3,%xmm14
|
|
+
|
|
+ # x10 += x15, x5 = rotl32(x5 ^ x10, 12)
|
|
+ paddd %xmm15,%xmm10
|
|
+ pxor %xmm10,%xmm5
|
|
+ movdqa %xmm5,%xmm0
|
|
+ pslld $12,%xmm0
|
|
+ psrld $20,%xmm5
|
|
+ por %xmm0,%xmm5
|
|
+ # x11 += x12, x6 = rotl32(x6 ^ x11, 12)
|
|
+ paddd %xmm12,%xmm11
|
|
+ pxor %xmm11,%xmm6
|
|
+ movdqa %xmm6,%xmm0
|
|
+ pslld $12,%xmm0
|
|
+ psrld $20,%xmm6
|
|
+ por %xmm0,%xmm6
|
|
+ # x8 += x13, x7 = rotl32(x7 ^ x8, 12)
|
|
+ paddd %xmm13,%xmm8
|
|
+ pxor %xmm8,%xmm7
|
|
+ movdqa %xmm7,%xmm0
|
|
+ pslld $12,%xmm0
|
|
+ psrld $20,%xmm7
|
|
+ por %xmm0,%xmm7
|
|
+ # x9 += x14, x4 = rotl32(x4 ^ x9, 12)
|
|
+ paddd %xmm14,%xmm9
|
|
+ pxor %xmm9,%xmm4
|
|
+ movdqa %xmm4,%xmm0
|
|
+ pslld $12,%xmm0
|
|
+ psrld $20,%xmm4
|
|
+ por %xmm0,%xmm4
|
|
+
|
|
+ # x0 += x5, x15 = rotl32(x15 ^ x0, 8)
|
|
+ movdqa 0x00(%rsp),%xmm0
|
|
+ paddd %xmm5,%xmm0
|
|
+ movdqa %xmm0,0x00(%rsp)
|
|
+ pxor %xmm0,%xmm15
|
|
+ pshufb %xmm2,%xmm15
|
|
+ # x1 += x6, x12 = rotl32(x12 ^ x1, 8)
|
|
+ movdqa 0x10(%rsp),%xmm0
|
|
+ paddd %xmm6,%xmm0
|
|
+ movdqa %xmm0,0x10(%rsp)
|
|
+ pxor %xmm0,%xmm12
|
|
+ pshufb %xmm2,%xmm12
|
|
+ # x2 += x7, x13 = rotl32(x13 ^ x2, 8)
|
|
+ movdqa 0x20(%rsp),%xmm0
|
|
+ paddd %xmm7,%xmm0
|
|
+ movdqa %xmm0,0x20(%rsp)
|
|
+ pxor %xmm0,%xmm13
|
|
+ pshufb %xmm2,%xmm13
|
|
+ # x3 += x4, x14 = rotl32(x14 ^ x3, 8)
|
|
+ movdqa 0x30(%rsp),%xmm0
|
|
+ paddd %xmm4,%xmm0
|
|
+ movdqa %xmm0,0x30(%rsp)
|
|
+ pxor %xmm0,%xmm14
|
|
+ pshufb %xmm2,%xmm14
|
|
+
|
|
+ # x10 += x15, x5 = rotl32(x5 ^ x10, 7)
|
|
+ paddd %xmm15,%xmm10
|
|
+ pxor %xmm10,%xmm5
|
|
+ movdqa %xmm5,%xmm0
|
|
+ pslld $7,%xmm0
|
|
+ psrld $25,%xmm5
|
|
+ por %xmm0,%xmm5
|
|
+ # x11 += x12, x6 = rotl32(x6 ^ x11, 7)
|
|
+ paddd %xmm12,%xmm11
|
|
+ pxor %xmm11,%xmm6
|
|
+ movdqa %xmm6,%xmm0
|
|
+ pslld $7,%xmm0
|
|
+ psrld $25,%xmm6
|
|
+ por %xmm0,%xmm6
|
|
+ # x8 += x13, x7 = rotl32(x7 ^ x8, 7)
|
|
+ paddd %xmm13,%xmm8
|
|
+ pxor %xmm8,%xmm7
|
|
+ movdqa %xmm7,%xmm0
|
|
+ pslld $7,%xmm0
|
|
+ psrld $25,%xmm7
|
|
+ por %xmm0,%xmm7
|
|
+ # x9 += x14, x4 = rotl32(x4 ^ x9, 7)
|
|
+ paddd %xmm14,%xmm9
|
|
+ pxor %xmm9,%xmm4
|
|
+ movdqa %xmm4,%xmm0
|
|
+ pslld $7,%xmm0
|
|
+ psrld $25,%xmm4
|
|
+ por %xmm0,%xmm4
|
|
+
|
|
+ dec %ecx
|
|
+ jnz .Ldoubleround4
|
|
+
|
|
+ # x0[0-3] += s0[0]
|
|
+ # x1[0-3] += s0[1]
|
|
+ movq 0x00(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ paddd 0x00(%rsp),%xmm2
|
|
+ movdqa %xmm2,0x00(%rsp)
|
|
+ paddd 0x10(%rsp),%xmm3
|
|
+ movdqa %xmm3,0x10(%rsp)
|
|
+ # x2[0-3] += s0[2]
|
|
+ # x3[0-3] += s0[3]
|
|
+ movq 0x08(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ paddd 0x20(%rsp),%xmm2
|
|
+ movdqa %xmm2,0x20(%rsp)
|
|
+ paddd 0x30(%rsp),%xmm3
|
|
+ movdqa %xmm3,0x30(%rsp)
|
|
+
|
|
+ # x4[0-3] += s1[0]
|
|
+ # x5[0-3] += s1[1]
|
|
+ movq 0x10(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ paddd %xmm2,%xmm4
|
|
+ paddd %xmm3,%xmm5
|
|
+ # x6[0-3] += s1[2]
|
|
+ # x7[0-3] += s1[3]
|
|
+ movq 0x18(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ paddd %xmm2,%xmm6
|
|
+ paddd %xmm3,%xmm7
|
|
+
|
|
+ # x8[0-3] += s2[0]
|
|
+ # x9[0-3] += s2[1]
|
|
+ movq 0x20(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ paddd %xmm2,%xmm8
|
|
+ paddd %xmm3,%xmm9
|
|
+ # x10[0-3] += s2[2]
|
|
+ # x11[0-3] += s2[3]
|
|
+ movq 0x28(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ paddd %xmm2,%xmm10
|
|
+ paddd %xmm3,%xmm11
|
|
+
|
|
+ # x12[0-3] += s3[0]
|
|
+ # x13[0-3] += s3[1]
|
|
+ movq 0x30(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ paddd %xmm2,%xmm12
|
|
+ paddd %xmm3,%xmm13
|
|
+ # x14[0-3] += s3[2]
|
|
+ # x15[0-3] += s3[3]
|
|
+ movq 0x38(%rdi),%xmm3
|
|
+ pshufd $0x00,%xmm3,%xmm2
|
|
+ pshufd $0x55,%xmm3,%xmm3
|
|
+ paddd %xmm2,%xmm14
|
|
+ paddd %xmm3,%xmm15
|
|
+
|
|
+ # x12 += counter values 0-3
|
|
+ paddd %xmm1,%xmm12
|
|
+
|
|
+ # interleave 32-bit words in state n, n+1
|
|
+ movdqa 0x00(%rsp),%xmm0
|
|
+ movdqa 0x10(%rsp),%xmm1
|
|
+ movdqa %xmm0,%xmm2
|
|
+ punpckldq %xmm1,%xmm2
|
|
+ punpckhdq %xmm1,%xmm0
|
|
+ movdqa %xmm2,0x00(%rsp)
|
|
+ movdqa %xmm0,0x10(%rsp)
|
|
+ movdqa 0x20(%rsp),%xmm0
|
|
+ movdqa 0x30(%rsp),%xmm1
|
|
+ movdqa %xmm0,%xmm2
|
|
+ punpckldq %xmm1,%xmm2
|
|
+ punpckhdq %xmm1,%xmm0
|
|
+ movdqa %xmm2,0x20(%rsp)
|
|
+ movdqa %xmm0,0x30(%rsp)
|
|
+ movdqa %xmm4,%xmm0
|
|
+ punpckldq %xmm5,%xmm4
|
|
+ punpckhdq %xmm5,%xmm0
|
|
+ movdqa %xmm0,%xmm5
|
|
+ movdqa %xmm6,%xmm0
|
|
+ punpckldq %xmm7,%xmm6
|
|
+ punpckhdq %xmm7,%xmm0
|
|
+ movdqa %xmm0,%xmm7
|
|
+ movdqa %xmm8,%xmm0
|
|
+ punpckldq %xmm9,%xmm8
|
|
+ punpckhdq %xmm9,%xmm0
|
|
+ movdqa %xmm0,%xmm9
|
|
+ movdqa %xmm10,%xmm0
|
|
+ punpckldq %xmm11,%xmm10
|
|
+ punpckhdq %xmm11,%xmm0
|
|
+ movdqa %xmm0,%xmm11
|
|
+ movdqa %xmm12,%xmm0
|
|
+ punpckldq %xmm13,%xmm12
|
|
+ punpckhdq %xmm13,%xmm0
|
|
+ movdqa %xmm0,%xmm13
|
|
+ movdqa %xmm14,%xmm0
|
|
+ punpckldq %xmm15,%xmm14
|
|
+ punpckhdq %xmm15,%xmm0
|
|
+ movdqa %xmm0,%xmm15
|
|
+
|
|
+ # interleave 64-bit words in state n, n+2
|
|
+ movdqa 0x00(%rsp),%xmm0
|
|
+ movdqa 0x20(%rsp),%xmm1
|
|
+ movdqa %xmm0,%xmm2
|
|
+ punpcklqdq %xmm1,%xmm2
|
|
+ punpckhqdq %xmm1,%xmm0
|
|
+ movdqa %xmm2,0x00(%rsp)
|
|
+ movdqa %xmm0,0x20(%rsp)
|
|
+ movdqa 0x10(%rsp),%xmm0
|
|
+ movdqa 0x30(%rsp),%xmm1
|
|
+ movdqa %xmm0,%xmm2
|
|
+ punpcklqdq %xmm1,%xmm2
|
|
+ punpckhqdq %xmm1,%xmm0
|
|
+ movdqa %xmm2,0x10(%rsp)
|
|
+ movdqa %xmm0,0x30(%rsp)
|
|
+ movdqa %xmm4,%xmm0
|
|
+ punpcklqdq %xmm6,%xmm4
|
|
+ punpckhqdq %xmm6,%xmm0
|
|
+ movdqa %xmm0,%xmm6
|
|
+ movdqa %xmm5,%xmm0
|
|
+ punpcklqdq %xmm7,%xmm5
|
|
+ punpckhqdq %xmm7,%xmm0
|
|
+ movdqa %xmm0,%xmm7
|
|
+ movdqa %xmm8,%xmm0
|
|
+ punpcklqdq %xmm10,%xmm8
|
|
+ punpckhqdq %xmm10,%xmm0
|
|
+ movdqa %xmm0,%xmm10
|
|
+ movdqa %xmm9,%xmm0
|
|
+ punpcklqdq %xmm11,%xmm9
|
|
+ punpckhqdq %xmm11,%xmm0
|
|
+ movdqa %xmm0,%xmm11
|
|
+ movdqa %xmm12,%xmm0
|
|
+ punpcklqdq %xmm14,%xmm12
|
|
+ punpckhqdq %xmm14,%xmm0
|
|
+ movdqa %xmm0,%xmm14
|
|
+ movdqa %xmm13,%xmm0
|
|
+ punpcklqdq %xmm15,%xmm13
|
|
+ punpckhqdq %xmm15,%xmm0
|
|
+ movdqa %xmm0,%xmm15
|
|
+
|
|
+ # xor with corresponding input, write to output
|
|
+ movdqa 0x00(%rsp),%xmm0
|
|
+ movdqu 0x00(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm0
|
|
+ movdqu %xmm0,0x00(%rsi)
|
|
+ movdqa 0x10(%rsp),%xmm0
|
|
+ movdqu 0x80(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm0
|
|
+ movdqu %xmm0,0x80(%rsi)
|
|
+ movdqa 0x20(%rsp),%xmm0
|
|
+ movdqu 0x40(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm0
|
|
+ movdqu %xmm0,0x40(%rsi)
|
|
+ movdqa 0x30(%rsp),%xmm0
|
|
+ movdqu 0xc0(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm0
|
|
+ movdqu %xmm0,0xc0(%rsi)
|
|
+ movdqu 0x10(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm4
|
|
+ movdqu %xmm4,0x10(%rsi)
|
|
+ movdqu 0x90(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm5
|
|
+ movdqu %xmm5,0x90(%rsi)
|
|
+ movdqu 0x50(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm6
|
|
+ movdqu %xmm6,0x50(%rsi)
|
|
+ movdqu 0xd0(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm7
|
|
+ movdqu %xmm7,0xd0(%rsi)
|
|
+ movdqu 0x20(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm8
|
|
+ movdqu %xmm8,0x20(%rsi)
|
|
+ movdqu 0xa0(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm9
|
|
+ movdqu %xmm9,0xa0(%rsi)
|
|
+ movdqu 0x60(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm10
|
|
+ movdqu %xmm10,0x60(%rsi)
|
|
+ movdqu 0xe0(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm11
|
|
+ movdqu %xmm11,0xe0(%rsi)
|
|
+ movdqu 0x30(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm12
|
|
+ movdqu %xmm12,0x30(%rsi)
|
|
+ movdqu 0xb0(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm13
|
|
+ movdqu %xmm13,0xb0(%rsi)
|
|
+ movdqu 0x70(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm14
|
|
+ movdqu %xmm14,0x70(%rsi)
|
|
+ movdqu 0xf0(%rdx),%xmm1
|
|
+ pxor %xmm1,%xmm15
|
|
+ movdqu %xmm15,0xf0(%rsi)
|
|
+
|
|
+ mov %r11,%rsp
|
|
+ ret
|
|
+ENDPROC(chacha20_asm_4block_xor_ssse3)
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/poly1305-avx2-x86_64.S
|
|
@@ -0,0 +1,386 @@
|
|
+/*
|
|
+ * Poly1305 authenticator algorithm, RFC7539, x64 AVX2 functions
|
|
+ *
|
|
+ * Copyright (C) 2015 Martin Willi
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <linux/linkage.h>
|
|
+
|
|
+.data
|
|
+.align 32
|
|
+
|
|
+ANMASK: .octa 0x0000000003ffffff0000000003ffffff
|
|
+ .octa 0x0000000003ffffff0000000003ffffff
|
|
+ORMASK: .octa 0x00000000010000000000000001000000
|
|
+ .octa 0x00000000010000000000000001000000
|
|
+
|
|
+.text
|
|
+
|
|
+#define h0 0x00(%rdi)
|
|
+#define h1 0x04(%rdi)
|
|
+#define h2 0x08(%rdi)
|
|
+#define h3 0x0c(%rdi)
|
|
+#define h4 0x10(%rdi)
|
|
+#define r0 0x00(%rdx)
|
|
+#define r1 0x04(%rdx)
|
|
+#define r2 0x08(%rdx)
|
|
+#define r3 0x0c(%rdx)
|
|
+#define r4 0x10(%rdx)
|
|
+#define u0 0x00(%r8)
|
|
+#define u1 0x04(%r8)
|
|
+#define u2 0x08(%r8)
|
|
+#define u3 0x0c(%r8)
|
|
+#define u4 0x10(%r8)
|
|
+#define w0 0x14(%r8)
|
|
+#define w1 0x18(%r8)
|
|
+#define w2 0x1c(%r8)
|
|
+#define w3 0x20(%r8)
|
|
+#define w4 0x24(%r8)
|
|
+#define y0 0x28(%r8)
|
|
+#define y1 0x2c(%r8)
|
|
+#define y2 0x30(%r8)
|
|
+#define y3 0x34(%r8)
|
|
+#define y4 0x38(%r8)
|
|
+#define m %rsi
|
|
+#define hc0 %ymm0
|
|
+#define hc1 %ymm1
|
|
+#define hc2 %ymm2
|
|
+#define hc3 %ymm3
|
|
+#define hc4 %ymm4
|
|
+#define hc0x %xmm0
|
|
+#define hc1x %xmm1
|
|
+#define hc2x %xmm2
|
|
+#define hc3x %xmm3
|
|
+#define hc4x %xmm4
|
|
+#define t1 %ymm5
|
|
+#define t2 %ymm6
|
|
+#define t1x %xmm5
|
|
+#define t2x %xmm6
|
|
+#define ruwy0 %ymm7
|
|
+#define ruwy1 %ymm8
|
|
+#define ruwy2 %ymm9
|
|
+#define ruwy3 %ymm10
|
|
+#define ruwy4 %ymm11
|
|
+#define ruwy0x %xmm7
|
|
+#define ruwy1x %xmm8
|
|
+#define ruwy2x %xmm9
|
|
+#define ruwy3x %xmm10
|
|
+#define ruwy4x %xmm11
|
|
+#define svxz1 %ymm12
|
|
+#define svxz2 %ymm13
|
|
+#define svxz3 %ymm14
|
|
+#define svxz4 %ymm15
|
|
+#define d0 %r9
|
|
+#define d1 %r10
|
|
+#define d2 %r11
|
|
+#define d3 %r12
|
|
+#define d4 %r13
|
|
+
|
|
+ENTRY(poly1305_asm_4block_avx2)
|
|
+ # %rdi: Accumulator h[5]
|
|
+ # %rsi: 64 byte input block m
|
|
+ # %rdx: Poly1305 key r[5]
|
|
+ # %rcx: Quadblock count
|
|
+ # %r8: Poly1305 derived key r^2 u[5], r^3 w[5], r^4 y[5],
|
|
+
|
|
+ # This four-block variant uses loop unrolled block processing. It
|
|
+ # requires 4 Poly1305 keys: r, r^2, r^3 and r^4:
|
|
+ # h = (h + m) * r => h = (h + m1) * r^4 + m2 * r^3 + m3 * r^2 + m4 * r
|
|
+
|
|
+ vzeroupper
|
|
+ push %rbx
|
|
+ push %r12
|
|
+ push %r13
|
|
+
|
|
+ # combine r0,u0,w0,y0
|
|
+ vmovd y0,ruwy0x
|
|
+ vmovd w0,t1x
|
|
+ vpunpcklqdq t1,ruwy0,ruwy0
|
|
+ vmovd u0,t1x
|
|
+ vmovd r0,t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,ruwy0,ruwy0
|
|
+
|
|
+ # combine r1,u1,w1,y1 and s1=r1*5,v1=u1*5,x1=w1*5,z1=y1*5
|
|
+ vmovd y1,ruwy1x
|
|
+ vmovd w1,t1x
|
|
+ vpunpcklqdq t1,ruwy1,ruwy1
|
|
+ vmovd u1,t1x
|
|
+ vmovd r1,t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,ruwy1,ruwy1
|
|
+ vpslld $2,ruwy1,svxz1
|
|
+ vpaddd ruwy1,svxz1,svxz1
|
|
+
|
|
+ # combine r2,u2,w2,y2 and s2=r2*5,v2=u2*5,x2=w2*5,z2=y2*5
|
|
+ vmovd y2,ruwy2x
|
|
+ vmovd w2,t1x
|
|
+ vpunpcklqdq t1,ruwy2,ruwy2
|
|
+ vmovd u2,t1x
|
|
+ vmovd r2,t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,ruwy2,ruwy2
|
|
+ vpslld $2,ruwy2,svxz2
|
|
+ vpaddd ruwy2,svxz2,svxz2
|
|
+
|
|
+ # combine r3,u3,w3,y3 and s3=r3*5,v3=u3*5,x3=w3*5,z3=y3*5
|
|
+ vmovd y3,ruwy3x
|
|
+ vmovd w3,t1x
|
|
+ vpunpcklqdq t1,ruwy3,ruwy3
|
|
+ vmovd u3,t1x
|
|
+ vmovd r3,t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,ruwy3,ruwy3
|
|
+ vpslld $2,ruwy3,svxz3
|
|
+ vpaddd ruwy3,svxz3,svxz3
|
|
+
|
|
+ # combine r4,u4,w4,y4 and s4=r4*5,v4=u4*5,x4=w4*5,z4=y4*5
|
|
+ vmovd y4,ruwy4x
|
|
+ vmovd w4,t1x
|
|
+ vpunpcklqdq t1,ruwy4,ruwy4
|
|
+ vmovd u4,t1x
|
|
+ vmovd r4,t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,ruwy4,ruwy4
|
|
+ vpslld $2,ruwy4,svxz4
|
|
+ vpaddd ruwy4,svxz4,svxz4
|
|
+
|
|
+.Ldoblock4:
|
|
+ # hc0 = [m[48-51] & 0x3ffffff, m[32-35] & 0x3ffffff,
|
|
+ # m[16-19] & 0x3ffffff, m[ 0- 3] & 0x3ffffff + h0]
|
|
+ vmovd 0x00(m),hc0x
|
|
+ vmovd 0x10(m),t1x
|
|
+ vpunpcklqdq t1,hc0,hc0
|
|
+ vmovd 0x20(m),t1x
|
|
+ vmovd 0x30(m),t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,hc0,hc0
|
|
+ vpand ANMASK(%rip),hc0,hc0
|
|
+ vmovd h0,t1x
|
|
+ vpaddd t1,hc0,hc0
|
|
+ # hc1 = [(m[51-54] >> 2) & 0x3ffffff, (m[35-38] >> 2) & 0x3ffffff,
|
|
+ # (m[19-22] >> 2) & 0x3ffffff, (m[ 3- 6] >> 2) & 0x3ffffff + h1]
|
|
+ vmovd 0x03(m),hc1x
|
|
+ vmovd 0x13(m),t1x
|
|
+ vpunpcklqdq t1,hc1,hc1
|
|
+ vmovd 0x23(m),t1x
|
|
+ vmovd 0x33(m),t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,hc1,hc1
|
|
+ vpsrld $2,hc1,hc1
|
|
+ vpand ANMASK(%rip),hc1,hc1
|
|
+ vmovd h1,t1x
|
|
+ vpaddd t1,hc1,hc1
|
|
+ # hc2 = [(m[54-57] >> 4) & 0x3ffffff, (m[38-41] >> 4) & 0x3ffffff,
|
|
+ # (m[22-25] >> 4) & 0x3ffffff, (m[ 6- 9] >> 4) & 0x3ffffff + h2]
|
|
+ vmovd 0x06(m),hc2x
|
|
+ vmovd 0x16(m),t1x
|
|
+ vpunpcklqdq t1,hc2,hc2
|
|
+ vmovd 0x26(m),t1x
|
|
+ vmovd 0x36(m),t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,hc2,hc2
|
|
+ vpsrld $4,hc2,hc2
|
|
+ vpand ANMASK(%rip),hc2,hc2
|
|
+ vmovd h2,t1x
|
|
+ vpaddd t1,hc2,hc2
|
|
+ # hc3 = [(m[57-60] >> 6) & 0x3ffffff, (m[41-44] >> 6) & 0x3ffffff,
|
|
+ # (m[25-28] >> 6) & 0x3ffffff, (m[ 9-12] >> 6) & 0x3ffffff + h3]
|
|
+ vmovd 0x09(m),hc3x
|
|
+ vmovd 0x19(m),t1x
|
|
+ vpunpcklqdq t1,hc3,hc3
|
|
+ vmovd 0x29(m),t1x
|
|
+ vmovd 0x39(m),t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,hc3,hc3
|
|
+ vpsrld $6,hc3,hc3
|
|
+ vpand ANMASK(%rip),hc3,hc3
|
|
+ vmovd h3,t1x
|
|
+ vpaddd t1,hc3,hc3
|
|
+ # hc4 = [(m[60-63] >> 8) | (1<<24), (m[44-47] >> 8) | (1<<24),
|
|
+ # (m[28-31] >> 8) | (1<<24), (m[12-15] >> 8) | (1<<24) + h4]
|
|
+ vmovd 0x0c(m),hc4x
|
|
+ vmovd 0x1c(m),t1x
|
|
+ vpunpcklqdq t1,hc4,hc4
|
|
+ vmovd 0x2c(m),t1x
|
|
+ vmovd 0x3c(m),t2x
|
|
+ vpunpcklqdq t2,t1,t1
|
|
+ vperm2i128 $0x20,t1,hc4,hc4
|
|
+ vpsrld $8,hc4,hc4
|
|
+ vpor ORMASK(%rip),hc4,hc4
|
|
+ vmovd h4,t1x
|
|
+ vpaddd t1,hc4,hc4
|
|
+
|
|
+ # t1 = [ hc0[3] * r0, hc0[2] * u0, hc0[1] * w0, hc0[0] * y0 ]
|
|
+ vpmuludq hc0,ruwy0,t1
|
|
+ # t1 += [ hc1[3] * s4, hc1[2] * v4, hc1[1] * x4, hc1[0] * z4 ]
|
|
+ vpmuludq hc1,svxz4,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc2[3] * s3, hc2[2] * v3, hc2[1] * x3, hc2[0] * z3 ]
|
|
+ vpmuludq hc2,svxz3,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc3[3] * s2, hc3[2] * v2, hc3[1] * x2, hc3[0] * z2 ]
|
|
+ vpmuludq hc3,svxz2,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc4[3] * s1, hc4[2] * v1, hc4[1] * x1, hc4[0] * z1 ]
|
|
+ vpmuludq hc4,svxz1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # d0 = t1[0] + t1[1] + t[2] + t[3]
|
|
+ vpermq $0xee,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vpsrldq $8,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vmovq t1x,d0
|
|
+
|
|
+ # t1 = [ hc0[3] * r1, hc0[2] * u1,hc0[1] * w1, hc0[0] * y1 ]
|
|
+ vpmuludq hc0,ruwy1,t1
|
|
+ # t1 += [ hc1[3] * r0, hc1[2] * u0, hc1[1] * w0, hc1[0] * y0 ]
|
|
+ vpmuludq hc1,ruwy0,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc2[3] * s4, hc2[2] * v4, hc2[1] * x4, hc2[0] * z4 ]
|
|
+ vpmuludq hc2,svxz4,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc3[3] * s3, hc3[2] * v3, hc3[1] * x3, hc3[0] * z3 ]
|
|
+ vpmuludq hc3,svxz3,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc4[3] * s2, hc4[2] * v2, hc4[1] * x2, hc4[0] * z2 ]
|
|
+ vpmuludq hc4,svxz2,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # d1 = t1[0] + t1[1] + t1[3] + t1[4]
|
|
+ vpermq $0xee,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vpsrldq $8,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vmovq t1x,d1
|
|
+
|
|
+ # t1 = [ hc0[3] * r2, hc0[2] * u2, hc0[1] * w2, hc0[0] * y2 ]
|
|
+ vpmuludq hc0,ruwy2,t1
|
|
+ # t1 += [ hc1[3] * r1, hc1[2] * u1, hc1[1] * w1, hc1[0] * y1 ]
|
|
+ vpmuludq hc1,ruwy1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc2[3] * r0, hc2[2] * u0, hc2[1] * w0, hc2[0] * y0 ]
|
|
+ vpmuludq hc2,ruwy0,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc3[3] * s4, hc3[2] * v4, hc3[1] * x4, hc3[0] * z4 ]
|
|
+ vpmuludq hc3,svxz4,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc4[3] * s3, hc4[2] * v3, hc4[1] * x3, hc4[0] * z3 ]
|
|
+ vpmuludq hc4,svxz3,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # d2 = t1[0] + t1[1] + t1[2] + t1[3]
|
|
+ vpermq $0xee,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vpsrldq $8,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vmovq t1x,d2
|
|
+
|
|
+ # t1 = [ hc0[3] * r3, hc0[2] * u3, hc0[1] * w3, hc0[0] * y3 ]
|
|
+ vpmuludq hc0,ruwy3,t1
|
|
+ # t1 += [ hc1[3] * r2, hc1[2] * u2, hc1[1] * w2, hc1[0] * y2 ]
|
|
+ vpmuludq hc1,ruwy2,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc2[3] * r1, hc2[2] * u1, hc2[1] * w1, hc2[0] * y1 ]
|
|
+ vpmuludq hc2,ruwy1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc3[3] * r0, hc3[2] * u0, hc3[1] * w0, hc3[0] * y0 ]
|
|
+ vpmuludq hc3,ruwy0,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc4[3] * s4, hc4[2] * v4, hc4[1] * x4, hc4[0] * z4 ]
|
|
+ vpmuludq hc4,svxz4,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # d3 = t1[0] + t1[1] + t1[2] + t1[3]
|
|
+ vpermq $0xee,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vpsrldq $8,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vmovq t1x,d3
|
|
+
|
|
+ # t1 = [ hc0[3] * r4, hc0[2] * u4, hc0[1] * w4, hc0[0] * y4 ]
|
|
+ vpmuludq hc0,ruwy4,t1
|
|
+ # t1 += [ hc1[3] * r3, hc1[2] * u3, hc1[1] * w3, hc1[0] * y3 ]
|
|
+ vpmuludq hc1,ruwy3,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc2[3] * r2, hc2[2] * u2, hc2[1] * w2, hc2[0] * y2 ]
|
|
+ vpmuludq hc2,ruwy2,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc3[3] * r1, hc3[2] * u1, hc3[1] * w1, hc3[0] * y1 ]
|
|
+ vpmuludq hc3,ruwy1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # t1 += [ hc4[3] * r0, hc4[2] * u0, hc4[1] * w0, hc4[0] * y0 ]
|
|
+ vpmuludq hc4,ruwy0,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ # d4 = t1[0] + t1[1] + t1[2] + t1[3]
|
|
+ vpermq $0xee,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vpsrldq $8,t1,t2
|
|
+ vpaddq t2,t1,t1
|
|
+ vmovq t1x,d4
|
|
+
|
|
+ # d1 += d0 >> 26
|
|
+ mov d0,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d1
|
|
+ # h0 = d0 & 0x3ffffff
|
|
+ mov d0,%rbx
|
|
+ and $0x3ffffff,%ebx
|
|
+
|
|
+ # d2 += d1 >> 26
|
|
+ mov d1,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d2
|
|
+ # h1 = d1 & 0x3ffffff
|
|
+ mov d1,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h1
|
|
+
|
|
+ # d3 += d2 >> 26
|
|
+ mov d2,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d3
|
|
+ # h2 = d2 & 0x3ffffff
|
|
+ mov d2,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h2
|
|
+
|
|
+ # d4 += d3 >> 26
|
|
+ mov d3,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d4
|
|
+ # h3 = d3 & 0x3ffffff
|
|
+ mov d3,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h3
|
|
+
|
|
+ # h0 += (d4 >> 26) * 5
|
|
+ mov d4,%rax
|
|
+ shr $26,%rax
|
|
+ lea (%eax,%eax,4),%eax
|
|
+ add %eax,%ebx
|
|
+ # h4 = d4 & 0x3ffffff
|
|
+ mov d4,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h4
|
|
+
|
|
+ # h1 += h0 >> 26
|
|
+ mov %ebx,%eax
|
|
+ shr $26,%eax
|
|
+ add %eax,h1
|
|
+ # h0 = h0 & 0x3ffffff
|
|
+ andl $0x3ffffff,%ebx
|
|
+ mov %ebx,h0
|
|
+
|
|
+ add $0x40,m
|
|
+ dec %rcx
|
|
+ jnz .Ldoblock4
|
|
+
|
|
+ vzeroupper
|
|
+ pop %r13
|
|
+ pop %r12
|
|
+ pop %rbx
|
|
+ ret
|
|
+ENDPROC(poly1305_asm_4block_avx2)
|
|
--- /dev/null
|
|
+++ b/net/wireguard/crypto/poly1305-sse2-x86_64.S
|
|
@@ -0,0 +1,582 @@
|
|
+/*
|
|
+ * Poly1305 authenticator algorithm, RFC7539, x64 SSE2 functions
|
|
+ *
|
|
+ * Copyright (C) 2015 Martin Willi
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <linux/linkage.h>
|
|
+
|
|
+.data
|
|
+.align 16
|
|
+
|
|
+ANMASK: .octa 0x0000000003ffffff0000000003ffffff
|
|
+ORMASK: .octa 0x00000000010000000000000001000000
|
|
+
|
|
+.text
|
|
+
|
|
+#define h0 0x00(%rdi)
|
|
+#define h1 0x04(%rdi)
|
|
+#define h2 0x08(%rdi)
|
|
+#define h3 0x0c(%rdi)
|
|
+#define h4 0x10(%rdi)
|
|
+#define r0 0x00(%rdx)
|
|
+#define r1 0x04(%rdx)
|
|
+#define r2 0x08(%rdx)
|
|
+#define r3 0x0c(%rdx)
|
|
+#define r4 0x10(%rdx)
|
|
+#define s1 0x00(%rsp)
|
|
+#define s2 0x04(%rsp)
|
|
+#define s3 0x08(%rsp)
|
|
+#define s4 0x0c(%rsp)
|
|
+#define m %rsi
|
|
+#define h01 %xmm0
|
|
+#define h23 %xmm1
|
|
+#define h44 %xmm2
|
|
+#define t1 %xmm3
|
|
+#define t2 %xmm4
|
|
+#define t3 %xmm5
|
|
+#define t4 %xmm6
|
|
+#define mask %xmm7
|
|
+#define d0 %r8
|
|
+#define d1 %r9
|
|
+#define d2 %r10
|
|
+#define d3 %r11
|
|
+#define d4 %r12
|
|
+
|
|
+ENTRY(poly1305_asm_block_sse2)
|
|
+ # %rdi: Accumulator h[5]
|
|
+ # %rsi: 16 byte input block m
|
|
+ # %rdx: Poly1305 key r[5]
|
|
+ # %rcx: Block count
|
|
+
|
|
+ # This single block variant tries to improve performance by doing two
|
|
+ # multiplications in parallel using SSE instructions. There is quite
|
|
+ # some quardword packing involved, hence the speedup is marginal.
|
|
+
|
|
+ push %rbx
|
|
+ push %r12
|
|
+ sub $0x10,%rsp
|
|
+
|
|
+ # s1..s4 = r1..r4 * 5
|
|
+ mov r1,%eax
|
|
+ lea (%eax,%eax,4),%eax
|
|
+ mov %eax,s1
|
|
+ mov r2,%eax
|
|
+ lea (%eax,%eax,4),%eax
|
|
+ mov %eax,s2
|
|
+ mov r3,%eax
|
|
+ lea (%eax,%eax,4),%eax
|
|
+ mov %eax,s3
|
|
+ mov r4,%eax
|
|
+ lea (%eax,%eax,4),%eax
|
|
+ mov %eax,s4
|
|
+
|
|
+ movdqa ANMASK(%rip),mask
|
|
+
|
|
+.Ldoblock:
|
|
+ # h01 = [0, h1, 0, h0]
|
|
+ # h23 = [0, h3, 0, h2]
|
|
+ # h44 = [0, h4, 0, h4]
|
|
+ movd h0,h01
|
|
+ movd h1,t1
|
|
+ movd h2,h23
|
|
+ movd h3,t2
|
|
+ movd h4,h44
|
|
+ punpcklqdq t1,h01
|
|
+ punpcklqdq t2,h23
|
|
+ punpcklqdq h44,h44
|
|
+
|
|
+ # h01 += [ (m[3-6] >> 2) & 0x3ffffff, m[0-3] & 0x3ffffff ]
|
|
+ movd 0x00(m),t1
|
|
+ movd 0x03(m),t2
|
|
+ psrld $2,t2
|
|
+ punpcklqdq t2,t1
|
|
+ pand mask,t1
|
|
+ paddd t1,h01
|
|
+ # h23 += [ (m[9-12] >> 6) & 0x3ffffff, (m[6-9] >> 4) & 0x3ffffff ]
|
|
+ movd 0x06(m),t1
|
|
+ movd 0x09(m),t2
|
|
+ psrld $4,t1
|
|
+ psrld $6,t2
|
|
+ punpcklqdq t2,t1
|
|
+ pand mask,t1
|
|
+ paddd t1,h23
|
|
+ # h44 += [ (m[12-15] >> 8) | (1 << 24), (m[12-15] >> 8) | (1 << 24) ]
|
|
+ mov 0x0c(m),%eax
|
|
+ shr $8,%eax
|
|
+ or $0x01000000,%eax
|
|
+ movd %eax,t1
|
|
+ pshufd $0xc4,t1,t1
|
|
+ paddd t1,h44
|
|
+
|
|
+ # t1[0] = h0 * r0 + h2 * s3
|
|
+ # t1[1] = h1 * s4 + h3 * s2
|
|
+ movd r0,t1
|
|
+ movd s4,t2
|
|
+ punpcklqdq t2,t1
|
|
+ pmuludq h01,t1
|
|
+ movd s3,t2
|
|
+ movd s2,t3
|
|
+ punpcklqdq t3,t2
|
|
+ pmuludq h23,t2
|
|
+ paddq t2,t1
|
|
+ # t2[0] = h0 * r1 + h2 * s4
|
|
+ # t2[1] = h1 * r0 + h3 * s3
|
|
+ movd r1,t2
|
|
+ movd r0,t3
|
|
+ punpcklqdq t3,t2
|
|
+ pmuludq h01,t2
|
|
+ movd s4,t3
|
|
+ movd s3,t4
|
|
+ punpcklqdq t4,t3
|
|
+ pmuludq h23,t3
|
|
+ paddq t3,t2
|
|
+ # t3[0] = h4 * s1
|
|
+ # t3[1] = h4 * s2
|
|
+ movd s1,t3
|
|
+ movd s2,t4
|
|
+ punpcklqdq t4,t3
|
|
+ pmuludq h44,t3
|
|
+ # d0 = t1[0] + t1[1] + t3[0]
|
|
+ # d1 = t2[0] + t2[1] + t3[1]
|
|
+ movdqa t1,t4
|
|
+ punpcklqdq t2,t4
|
|
+ punpckhqdq t2,t1
|
|
+ paddq t4,t1
|
|
+ paddq t3,t1
|
|
+ movq t1,d0
|
|
+ psrldq $8,t1
|
|
+ movq t1,d1
|
|
+
|
|
+ # t1[0] = h0 * r2 + h2 * r0
|
|
+ # t1[1] = h1 * r1 + h3 * s4
|
|
+ movd r2,t1
|
|
+ movd r1,t2
|
|
+ punpcklqdq t2,t1
|
|
+ pmuludq h01,t1
|
|
+ movd r0,t2
|
|
+ movd s4,t3
|
|
+ punpcklqdq t3,t2
|
|
+ pmuludq h23,t2
|
|
+ paddq t2,t1
|
|
+ # t2[0] = h0 * r3 + h2 * r1
|
|
+ # t2[1] = h1 * r2 + h3 * r0
|
|
+ movd r3,t2
|
|
+ movd r2,t3
|
|
+ punpcklqdq t3,t2
|
|
+ pmuludq h01,t2
|
|
+ movd r1,t3
|
|
+ movd r0,t4
|
|
+ punpcklqdq t4,t3
|
|
+ pmuludq h23,t3
|
|
+ paddq t3,t2
|
|
+ # t3[0] = h4 * s3
|
|
+ # t3[1] = h4 * s4
|
|
+ movd s3,t3
|
|
+ movd s4,t4
|
|
+ punpcklqdq t4,t3
|
|
+ pmuludq h44,t3
|
|
+ # d2 = t1[0] + t1[1] + t3[0]
|
|
+ # d3 = t2[0] + t2[1] + t3[1]
|
|
+ movdqa t1,t4
|
|
+ punpcklqdq t2,t4
|
|
+ punpckhqdq t2,t1
|
|
+ paddq t4,t1
|
|
+ paddq t3,t1
|
|
+ movq t1,d2
|
|
+ psrldq $8,t1
|
|
+ movq t1,d3
|
|
+
|
|
+ # t1[0] = h0 * r4 + h2 * r2
|
|
+ # t1[1] = h1 * r3 + h3 * r1
|
|
+ movd r4,t1
|
|
+ movd r3,t2
|
|
+ punpcklqdq t2,t1
|
|
+ pmuludq h01,t1
|
|
+ movd r2,t2
|
|
+ movd r1,t3
|
|
+ punpcklqdq t3,t2
|
|
+ pmuludq h23,t2
|
|
+ paddq t2,t1
|
|
+ # t3[0] = h4 * r0
|
|
+ movd r0,t3
|
|
+ pmuludq h44,t3
|
|
+ # d4 = t1[0] + t1[1] + t3[0]
|
|
+ movdqa t1,t4
|
|
+ psrldq $8,t4
|
|
+ paddq t4,t1
|
|
+ paddq t3,t1
|
|
+ movq t1,d4
|
|
+
|
|
+ # d1 += d0 >> 26
|
|
+ mov d0,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d1
|
|
+ # h0 = d0 & 0x3ffffff
|
|
+ mov d0,%rbx
|
|
+ and $0x3ffffff,%ebx
|
|
+
|
|
+ # d2 += d1 >> 26
|
|
+ mov d1,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d2
|
|
+ # h1 = d1 & 0x3ffffff
|
|
+ mov d1,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h1
|
|
+
|
|
+ # d3 += d2 >> 26
|
|
+ mov d2,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d3
|
|
+ # h2 = d2 & 0x3ffffff
|
|
+ mov d2,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h2
|
|
+
|
|
+ # d4 += d3 >> 26
|
|
+ mov d3,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d4
|
|
+ # h3 = d3 & 0x3ffffff
|
|
+ mov d3,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h3
|
|
+
|
|
+ # h0 += (d4 >> 26) * 5
|
|
+ mov d4,%rax
|
|
+ shr $26,%rax
|
|
+ lea (%eax,%eax,4),%eax
|
|
+ add %eax,%ebx
|
|
+ # h4 = d4 & 0x3ffffff
|
|
+ mov d4,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h4
|
|
+
|
|
+ # h1 += h0 >> 26
|
|
+ mov %ebx,%eax
|
|
+ shr $26,%eax
|
|
+ add %eax,h1
|
|
+ # h0 = h0 & 0x3ffffff
|
|
+ andl $0x3ffffff,%ebx
|
|
+ mov %ebx,h0
|
|
+
|
|
+ add $0x10,m
|
|
+ dec %rcx
|
|
+ jnz .Ldoblock
|
|
+
|
|
+ add $0x10,%rsp
|
|
+ pop %r12
|
|
+ pop %rbx
|
|
+ ret
|
|
+ENDPROC(poly1305_asm_block_sse2)
|
|
+
|
|
+
|
|
+#define u0 0x00(%r8)
|
|
+#define u1 0x04(%r8)
|
|
+#define u2 0x08(%r8)
|
|
+#define u3 0x0c(%r8)
|
|
+#define u4 0x10(%r8)
|
|
+#define hc0 %xmm0
|
|
+#define hc1 %xmm1
|
|
+#define hc2 %xmm2
|
|
+#define hc3 %xmm5
|
|
+#define hc4 %xmm6
|
|
+#define ru0 %xmm7
|
|
+#define ru1 %xmm8
|
|
+#define ru2 %xmm9
|
|
+#define ru3 %xmm10
|
|
+#define ru4 %xmm11
|
|
+#define sv1 %xmm12
|
|
+#define sv2 %xmm13
|
|
+#define sv3 %xmm14
|
|
+#define sv4 %xmm15
|
|
+#undef d0
|
|
+#define d0 %r13
|
|
+
|
|
+ENTRY(poly1305_asm_2block_sse2)
|
|
+ # %rdi: Accumulator h[5]
|
|
+ # %rsi: 16 byte input block m
|
|
+ # %rdx: Poly1305 key r[5]
|
|
+ # %rcx: Doubleblock count
|
|
+ # %r8: Poly1305 derived key r^2 u[5]
|
|
+
|
|
+ # This two-block variant further improves performance by using loop
|
|
+ # unrolled block processing. This is more straight forward and does
|
|
+ # less byte shuffling, but requires a second Poly1305 key r^2:
|
|
+ # h = (h + m) * r => h = (h + m1) * r^2 + m2 * r
|
|
+
|
|
+ push %rbx
|
|
+ push %r12
|
|
+ push %r13
|
|
+
|
|
+ # combine r0,u0
|
|
+ movd u0,ru0
|
|
+ movd r0,t1
|
|
+ punpcklqdq t1,ru0
|
|
+
|
|
+ # combine r1,u1 and s1=r1*5,v1=u1*5
|
|
+ movd u1,ru1
|
|
+ movd r1,t1
|
|
+ punpcklqdq t1,ru1
|
|
+ movdqa ru1,sv1
|
|
+ pslld $2,sv1
|
|
+ paddd ru1,sv1
|
|
+
|
|
+ # combine r2,u2 and s2=r2*5,v2=u2*5
|
|
+ movd u2,ru2
|
|
+ movd r2,t1
|
|
+ punpcklqdq t1,ru2
|
|
+ movdqa ru2,sv2
|
|
+ pslld $2,sv2
|
|
+ paddd ru2,sv2
|
|
+
|
|
+ # combine r3,u3 and s3=r3*5,v3=u3*5
|
|
+ movd u3,ru3
|
|
+ movd r3,t1
|
|
+ punpcklqdq t1,ru3
|
|
+ movdqa ru3,sv3
|
|
+ pslld $2,sv3
|
|
+ paddd ru3,sv3
|
|
+
|
|
+ # combine r4,u4 and s4=r4*5,v4=u4*5
|
|
+ movd u4,ru4
|
|
+ movd r4,t1
|
|
+ punpcklqdq t1,ru4
|
|
+ movdqa ru4,sv4
|
|
+ pslld $2,sv4
|
|
+ paddd ru4,sv4
|
|
+
|
|
+.Ldoblock2:
|
|
+ # hc0 = [ m[16-19] & 0x3ffffff, h0 + m[0-3] & 0x3ffffff ]
|
|
+ movd 0x00(m),hc0
|
|
+ movd 0x10(m),t1
|
|
+ punpcklqdq t1,hc0
|
|
+ pand ANMASK(%rip),hc0
|
|
+ movd h0,t1
|
|
+ paddd t1,hc0
|
|
+ # hc1 = [ (m[19-22] >> 2) & 0x3ffffff, h1 + (m[3-6] >> 2) & 0x3ffffff ]
|
|
+ movd 0x03(m),hc1
|
|
+ movd 0x13(m),t1
|
|
+ punpcklqdq t1,hc1
|
|
+ psrld $2,hc1
|
|
+ pand ANMASK(%rip),hc1
|
|
+ movd h1,t1
|
|
+ paddd t1,hc1
|
|
+ # hc2 = [ (m[22-25] >> 4) & 0x3ffffff, h2 + (m[6-9] >> 4) & 0x3ffffff ]
|
|
+ movd 0x06(m),hc2
|
|
+ movd 0x16(m),t1
|
|
+ punpcklqdq t1,hc2
|
|
+ psrld $4,hc2
|
|
+ pand ANMASK(%rip),hc2
|
|
+ movd h2,t1
|
|
+ paddd t1,hc2
|
|
+ # hc3 = [ (m[25-28] >> 6) & 0x3ffffff, h3 + (m[9-12] >> 6) & 0x3ffffff ]
|
|
+ movd 0x09(m),hc3
|
|
+ movd 0x19(m),t1
|
|
+ punpcklqdq t1,hc3
|
|
+ psrld $6,hc3
|
|
+ pand ANMASK(%rip),hc3
|
|
+ movd h3,t1
|
|
+ paddd t1,hc3
|
|
+ # hc4 = [ (m[28-31] >> 8) | (1<<24), h4 + (m[12-15] >> 8) | (1<<24) ]
|
|
+ movd 0x0c(m),hc4
|
|
+ movd 0x1c(m),t1
|
|
+ punpcklqdq t1,hc4
|
|
+ psrld $8,hc4
|
|
+ por ORMASK(%rip),hc4
|
|
+ movd h4,t1
|
|
+ paddd t1,hc4
|
|
+
|
|
+ # t1 = [ hc0[1] * r0, hc0[0] * u0 ]
|
|
+ movdqa ru0,t1
|
|
+ pmuludq hc0,t1
|
|
+ # t1 += [ hc1[1] * s4, hc1[0] * v4 ]
|
|
+ movdqa sv4,t2
|
|
+ pmuludq hc1,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc2[1] * s3, hc2[0] * v3 ]
|
|
+ movdqa sv3,t2
|
|
+ pmuludq hc2,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc3[1] * s2, hc3[0] * v2 ]
|
|
+ movdqa sv2,t2
|
|
+ pmuludq hc3,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc4[1] * s1, hc4[0] * v1 ]
|
|
+ movdqa sv1,t2
|
|
+ pmuludq hc4,t2
|
|
+ paddq t2,t1
|
|
+ # d0 = t1[0] + t1[1]
|
|
+ movdqa t1,t2
|
|
+ psrldq $8,t2
|
|
+ paddq t2,t1
|
|
+ movq t1,d0
|
|
+
|
|
+ # t1 = [ hc0[1] * r1, hc0[0] * u1 ]
|
|
+ movdqa ru1,t1
|
|
+ pmuludq hc0,t1
|
|
+ # t1 += [ hc1[1] * r0, hc1[0] * u0 ]
|
|
+ movdqa ru0,t2
|
|
+ pmuludq hc1,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc2[1] * s4, hc2[0] * v4 ]
|
|
+ movdqa sv4,t2
|
|
+ pmuludq hc2,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc3[1] * s3, hc3[0] * v3 ]
|
|
+ movdqa sv3,t2
|
|
+ pmuludq hc3,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc4[1] * s2, hc4[0] * v2 ]
|
|
+ movdqa sv2,t2
|
|
+ pmuludq hc4,t2
|
|
+ paddq t2,t1
|
|
+ # d1 = t1[0] + t1[1]
|
|
+ movdqa t1,t2
|
|
+ psrldq $8,t2
|
|
+ paddq t2,t1
|
|
+ movq t1,d1
|
|
+
|
|
+ # t1 = [ hc0[1] * r2, hc0[0] * u2 ]
|
|
+ movdqa ru2,t1
|
|
+ pmuludq hc0,t1
|
|
+ # t1 += [ hc1[1] * r1, hc1[0] * u1 ]
|
|
+ movdqa ru1,t2
|
|
+ pmuludq hc1,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc2[1] * r0, hc2[0] * u0 ]
|
|
+ movdqa ru0,t2
|
|
+ pmuludq hc2,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc3[1] * s4, hc3[0] * v4 ]
|
|
+ movdqa sv4,t2
|
|
+ pmuludq hc3,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc4[1] * s3, hc4[0] * v3 ]
|
|
+ movdqa sv3,t2
|
|
+ pmuludq hc4,t2
|
|
+ paddq t2,t1
|
|
+ # d2 = t1[0] + t1[1]
|
|
+ movdqa t1,t2
|
|
+ psrldq $8,t2
|
|
+ paddq t2,t1
|
|
+ movq t1,d2
|
|
+
|
|
+ # t1 = [ hc0[1] * r3, hc0[0] * u3 ]
|
|
+ movdqa ru3,t1
|
|
+ pmuludq hc0,t1
|
|
+ # t1 += [ hc1[1] * r2, hc1[0] * u2 ]
|
|
+ movdqa ru2,t2
|
|
+ pmuludq hc1,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc2[1] * r1, hc2[0] * u1 ]
|
|
+ movdqa ru1,t2
|
|
+ pmuludq hc2,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc3[1] * r0, hc3[0] * u0 ]
|
|
+ movdqa ru0,t2
|
|
+ pmuludq hc3,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc4[1] * s4, hc4[0] * v4 ]
|
|
+ movdqa sv4,t2
|
|
+ pmuludq hc4,t2
|
|
+ paddq t2,t1
|
|
+ # d3 = t1[0] + t1[1]
|
|
+ movdqa t1,t2
|
|
+ psrldq $8,t2
|
|
+ paddq t2,t1
|
|
+ movq t1,d3
|
|
+
|
|
+ # t1 = [ hc0[1] * r4, hc0[0] * u4 ]
|
|
+ movdqa ru4,t1
|
|
+ pmuludq hc0,t1
|
|
+ # t1 += [ hc1[1] * r3, hc1[0] * u3 ]
|
|
+ movdqa ru3,t2
|
|
+ pmuludq hc1,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc2[1] * r2, hc2[0] * u2 ]
|
|
+ movdqa ru2,t2
|
|
+ pmuludq hc2,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc3[1] * r1, hc3[0] * u1 ]
|
|
+ movdqa ru1,t2
|
|
+ pmuludq hc3,t2
|
|
+ paddq t2,t1
|
|
+ # t1 += [ hc4[1] * r0, hc4[0] * u0 ]
|
|
+ movdqa ru0,t2
|
|
+ pmuludq hc4,t2
|
|
+ paddq t2,t1
|
|
+ # d4 = t1[0] + t1[1]
|
|
+ movdqa t1,t2
|
|
+ psrldq $8,t2
|
|
+ paddq t2,t1
|
|
+ movq t1,d4
|
|
+
|
|
+ # d1 += d0 >> 26
|
|
+ mov d0,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d1
|
|
+ # h0 = d0 & 0x3ffffff
|
|
+ mov d0,%rbx
|
|
+ and $0x3ffffff,%ebx
|
|
+
|
|
+ # d2 += d1 >> 26
|
|
+ mov d1,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d2
|
|
+ # h1 = d1 & 0x3ffffff
|
|
+ mov d1,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h1
|
|
+
|
|
+ # d3 += d2 >> 26
|
|
+ mov d2,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d3
|
|
+ # h2 = d2 & 0x3ffffff
|
|
+ mov d2,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h2
|
|
+
|
|
+ # d4 += d3 >> 26
|
|
+ mov d3,%rax
|
|
+ shr $26,%rax
|
|
+ add %rax,d4
|
|
+ # h3 = d3 & 0x3ffffff
|
|
+ mov d3,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h3
|
|
+
|
|
+ # h0 += (d4 >> 26) * 5
|
|
+ mov d4,%rax
|
|
+ shr $26,%rax
|
|
+ lea (%eax,%eax,4),%eax
|
|
+ add %eax,%ebx
|
|
+ # h4 = d4 & 0x3ffffff
|
|
+ mov d4,%rax
|
|
+ and $0x3ffffff,%eax
|
|
+ mov %eax,h4
|
|
+
|
|
+ # h1 += h0 >> 26
|
|
+ mov %ebx,%eax
|
|
+ shr $26,%eax
|
|
+ add %eax,h1
|
|
+ # h0 = h0 & 0x3ffffff
|
|
+ andl $0x3ffffff,%ebx
|
|
+ mov %ebx,h0
|
|
+
|
|
+ add $0x20,m
|
|
+ dec %rcx
|
|
+ jnz .Ldoblock2
|
|
+
|
|
+ pop %r13
|
|
+ pop %r12
|
|
+ pop %rbx
|
|
+ ret
|
|
+ENDPROC(poly1305_asm_2block_sse2)
|
|
--- /dev/null
|
|
+++ b/net/wireguard/Makefile
|
|
@@ -0,0 +1,36 @@
|
|
+ccflags-y := -O3 -fvisibility=hidden
|
|
+ccflags-$(CONFIG_WIREGUARD_DEBUG) := -DDEBUG -g
|
|
+ccflags-y += -Wframe-larger-than=8192
|
|
+ccflags-y += -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt'
|
|
+wireguard-y := main.o noise.o device.o peer.o timers.o data.o send.o receive.o socket.o config.o hashtables.o routingtable.o ratelimiter.o cookie.o
|
|
+wireguard-y += crypto/curve25519.o crypto/chacha20poly1305.o crypto/blake2s.o
|
|
+ifeq ($(CONFIG_X86_64),y)
|
|
+ wireguard-y += crypto/chacha20-ssse3-x86_64.o crypto/poly1305-sse2-x86_64.o
|
|
+avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1$(comma)4)$(comma)%ymm2,yes,no)
|
|
+ifeq ($(avx2_supported),yes)
|
|
+ wireguard-y += crypto/chacha20-avx2-x86_64.o crypto/poly1305-avx2-x86_64.o
|
|
+endif
|
|
+endif
|
|
+
|
|
+include $(src)/compat/Makefile.include
|
|
+
|
|
+ifneq ($(KBUILD_EXTMOD),)
|
|
+CONFIG_WIREGUARD := m
|
|
+ifeq ($(CONFIG_WIREGUARD_PARALLEL),)
|
|
+ifneq (,$(filter $(CONFIG_PADATA),y m))
|
|
+ccflags-y += -DCONFIG_WIREGUARD_PARALLEL=y
|
|
+endif
|
|
+endif
|
|
+ifneq ($(CONFIG_MODULES),)
|
|
+ifeq ($(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT),)
|
|
+$(error "WireGuard requires CONFIG_NETFILTER_XT_MATCH_HASHLIMIT to be configured in your kernel. See https://www.wireguard.io/install/#kernel-requirements for more info")
|
|
+endif
|
|
+ifeq ($(CONFIG_PADATA),)
|
|
+ifneq ($(CONFIG_SMP),)
|
|
+$(warning "PEFORMANCE WARNING: WireGuard has enormous speed benefits when using CONFIG_PADATA on SMP systems. Please enable CONFIG_PADATA in your kernel configuration. See https://www.wireguard.io/install/#kernel-requirements for more info.")
|
|
+endif
|
|
+endif
|
|
+endif
|
|
+endif
|
|
+
|
|
+obj-$(CONFIG_WIREGUARD) := wireguard.o
|
|
--- /dev/null
|
|
+++ b/net/wireguard/Kconfig
|
|
@@ -0,0 +1,43 @@
|
|
+config WIREGUARD
|
|
+ tristate "IP: WireGuard secure network tunnel"
|
|
+ depends on NET && INET
|
|
+ select NET_UDP_TUNNEL
|
|
+ select NETFILTER_XT_MATCH_HASHLIMIT
|
|
+ select NETFILTER
|
|
+ select NETFILTER_XTABLES
|
|
+ select NETFILTER_ADVANCED
|
|
+ select CRYPTO_BLKCIPHER
|
|
+ select IP6_NF_IPTABLES if IPV6
|
|
+ default m
|
|
+ ---help---
|
|
+ WireGuard is a secure, fast, and easy to use replacement for IPSec
|
|
+ that uses modern cryptography and clever networking tricks. It's
|
|
+ designed to be fairly general purpose and abstract enough to fit most
|
|
+ use cases, while at the same time remaining extremely simple to
|
|
+ configure. See www.wireguard.io for more info.
|
|
+
|
|
+ It's safe to say Y or M here, as the driver is very lightweight and
|
|
+ is only in use when an administrator chooses to add an interface.
|
|
+
|
|
+config WIREGUARD_PARALLEL
|
|
+ bool "Enable parallel engine"
|
|
+ depends on SMP && WIREGUARD
|
|
+ select PADATA
|
|
+ default y
|
|
+ ---help---
|
|
+ This will allow WireGuard to utilize all CPU cores when encrypting
|
|
+ and decrypting packets.
|
|
+
|
|
+ It's safe to say Y here, and you probably should, as the performance
|
|
+ improvements are substantial.
|
|
+
|
|
+config WIREGUARD_DEBUG
|
|
+ bool "Debugging checks and verbose messages"
|
|
+ depends on WIREGUARD
|
|
+ ---help---
|
|
+ This will write log messages for handshake and other events
|
|
+ that occur for a WireGuard interface. It will also perform some
|
|
+ extra validation checks and unit tests at various points. This is
|
|
+ only useful for debugging.
|
|
+
|
|
+ Say N here unless you know what you're doing.
|
|
--- /dev/null
|
|
+++ b/net/wireguard/compat/Makefile.include
|
|
@@ -0,0 +1,11 @@
|
|
+ccflags-y += -include $(src)/compat/compat.h
|
|
+
|
|
+ifeq ($(wildcard $(srctree)/include/linux/siphash.h),)
|
|
+ccflags-y += -I$(src)/compat/siphash/include
|
|
+wireguard-y += compat/siphash/siphash.o
|
|
+endif
|
|
+
|
|
+ifeq ($(wildcard $(srctree)/include/net/dst_cache.h),)
|
|
+ccflags-y += -I$(src)/compat/dst_cache/include
|
|
+wireguard-y += compat/dst_cache/dst_cache.o
|
|
+endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/compat/siphash/include/linux/siphash.h
|
|
@@ -0,0 +1,140 @@
|
|
+/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ *
|
|
+ * This file is provided under a dual BSD/GPLv2 license.
|
|
+ *
|
|
+ * SipHash: a fast short-input PRF
|
|
+ * https://131002.net/siphash/
|
|
+ *
|
|
+ * This implementation is specifically for SipHash2-4 for a secure PRF
|
|
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
|
|
+ * hashtables.
|
|
+ */
|
|
+
|
|
+#ifndef _LINUX_SIPHASH_H
|
|
+#define _LINUX_SIPHASH_H
|
|
+
|
|
+#include <linux/types.h>
|
|
+#include <linux/kernel.h>
|
|
+
|
|
+#define SIPHASH_ALIGNMENT __alignof__(u64)
|
|
+typedef struct {
|
|
+ u64 key[2];
|
|
+} siphash_key_t;
|
|
+
|
|
+u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key);
|
|
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
|
+u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key);
|
|
+#endif
|
|
+
|
|
+u64 siphash_1u64(const u64 a, const siphash_key_t *key);
|
|
+u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key);
|
|
+u64 siphash_3u64(const u64 a, const u64 b, const u64 c,
|
|
+ const siphash_key_t *key);
|
|
+u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d,
|
|
+ const siphash_key_t *key);
|
|
+u64 siphash_1u32(const u32 a, const siphash_key_t *key);
|
|
+u64 siphash_3u32(const u32 a, const u32 b, const u32 c,
|
|
+ const siphash_key_t *key);
|
|
+
|
|
+static inline u64 siphash_2u32(const u32 a, const u32 b,
|
|
+ const siphash_key_t *key)
|
|
+{
|
|
+ return siphash_1u64((u64)b << 32 | a, key);
|
|
+}
|
|
+static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c,
|
|
+ const u32 d, const siphash_key_t *key)
|
|
+{
|
|
+ return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key);
|
|
+}
|
|
+
|
|
+
|
|
+static inline u64 ___siphash_aligned(const __le64 *data, size_t len,
|
|
+ const siphash_key_t *key)
|
|
+{
|
|
+ if (__builtin_constant_p(len) && len == 4)
|
|
+ return siphash_1u32(le32_to_cpup((const __le32 *)data), key);
|
|
+ if (__builtin_constant_p(len) && len == 8)
|
|
+ return siphash_1u64(le64_to_cpu(data[0]), key);
|
|
+ if (__builtin_constant_p(len) && len == 16)
|
|
+ return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
|
|
+ key);
|
|
+ if (__builtin_constant_p(len) && len == 24)
|
|
+ return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
|
|
+ le64_to_cpu(data[2]), key);
|
|
+ if (__builtin_constant_p(len) && len == 32)
|
|
+ return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
|
|
+ le64_to_cpu(data[2]), le64_to_cpu(data[3]),
|
|
+ key);
|
|
+ return __siphash_aligned(data, len, key);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * siphash - compute 64-bit siphash PRF value
|
|
+ * @data: buffer to hash
|
|
+ * @size: size of @data
|
|
+ * @key: the siphash key
|
|
+ */
|
|
+static inline u64 siphash(const void *data, size_t len,
|
|
+ const siphash_key_t *key)
|
|
+{
|
|
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
|
+ if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
|
|
+ return __siphash_unaligned(data, len, key);
|
|
+#endif
|
|
+ return ___siphash_aligned(data, len, key);
|
|
+}
|
|
+
|
|
+#define HSIPHASH_ALIGNMENT __alignof__(unsigned long)
|
|
+typedef struct {
|
|
+ unsigned long key[2];
|
|
+} hsiphash_key_t;
|
|
+
|
|
+u32 __hsiphash_aligned(const void *data, size_t len,
|
|
+ const hsiphash_key_t *key);
|
|
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
|
+u32 __hsiphash_unaligned(const void *data, size_t len,
|
|
+ const hsiphash_key_t *key);
|
|
+#endif
|
|
+
|
|
+u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key);
|
|
+u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key);
|
|
+u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c,
|
|
+ const hsiphash_key_t *key);
|
|
+u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d,
|
|
+ const hsiphash_key_t *key);
|
|
+
|
|
+static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len,
|
|
+ const hsiphash_key_t *key)
|
|
+{
|
|
+ if (__builtin_constant_p(len) && len == 4)
|
|
+ return hsiphash_1u32(le32_to_cpu(data[0]), key);
|
|
+ if (__builtin_constant_p(len) && len == 8)
|
|
+ return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
|
|
+ key);
|
|
+ if (__builtin_constant_p(len) && len == 12)
|
|
+ return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
|
|
+ le32_to_cpu(data[2]), key);
|
|
+ if (__builtin_constant_p(len) && len == 16)
|
|
+ return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
|
|
+ le32_to_cpu(data[2]), le32_to_cpu(data[3]),
|
|
+ key);
|
|
+ return __hsiphash_aligned(data, len, key);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * hsiphash - compute 32-bit hsiphash PRF value
|
|
+ * @data: buffer to hash
|
|
+ * @size: size of @data
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+static inline u32 hsiphash(const void *data, size_t len,
|
|
+ const hsiphash_key_t *key)
|
|
+{
|
|
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
|
+ if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
|
|
+ return __hsiphash_unaligned(data, len, key);
|
|
+#endif
|
|
+ return ___hsiphash_aligned(data, len, key);
|
|
+}
|
|
+
|
|
+#endif /* _LINUX_SIPHASH_H */
|
|
--- /dev/null
|
|
+++ b/net/wireguard/compat/siphash/siphash.c
|
|
@@ -0,0 +1,551 @@
|
|
+/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
+ *
|
|
+ * This file is provided under a dual BSD/GPLv2 license.
|
|
+ *
|
|
+ * SipHash: a fast short-input PRF
|
|
+ * https://131002.net/siphash/
|
|
+ *
|
|
+ * This implementation is specifically for SipHash2-4 for a secure PRF
|
|
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
|
|
+ * hashtables.
|
|
+ */
|
|
+
|
|
+#include <linux/siphash.h>
|
|
+#include <asm/unaligned.h>
|
|
+
|
|
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
|
|
+#include <linux/dcache.h>
|
|
+#include <asm/word-at-a-time.h>
|
|
+#endif
|
|
+
|
|
+#define SIPROUND \
|
|
+ do { \
|
|
+ v0 += v1; v1 = rol64(v1, 13); v1 ^= v0; v0 = rol64(v0, 32); \
|
|
+ v2 += v3; v3 = rol64(v3, 16); v3 ^= v2; \
|
|
+ v0 += v3; v3 = rol64(v3, 21); v3 ^= v0; \
|
|
+ v2 += v1; v1 = rol64(v1, 17); v1 ^= v2; v2 = rol64(v2, 32); \
|
|
+ } while (0)
|
|
+
|
|
+#define PREAMBLE(len) \
|
|
+ u64 v0 = 0x736f6d6570736575ULL; \
|
|
+ u64 v1 = 0x646f72616e646f6dULL; \
|
|
+ u64 v2 = 0x6c7967656e657261ULL; \
|
|
+ u64 v3 = 0x7465646279746573ULL; \
|
|
+ u64 b = ((u64)(len)) << 56; \
|
|
+ v3 ^= key->key[1]; \
|
|
+ v2 ^= key->key[0]; \
|
|
+ v1 ^= key->key[1]; \
|
|
+ v0 ^= key->key[0];
|
|
+
|
|
+#define POSTAMBLE \
|
|
+ v3 ^= b; \
|
|
+ SIPROUND; \
|
|
+ SIPROUND; \
|
|
+ v0 ^= b; \
|
|
+ v2 ^= 0xff; \
|
|
+ SIPROUND; \
|
|
+ SIPROUND; \
|
|
+ SIPROUND; \
|
|
+ SIPROUND; \
|
|
+ return (v0 ^ v1) ^ (v2 ^ v3);
|
|
+
|
|
+u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key)
|
|
+{
|
|
+ const u8 *end = data + len - (len % sizeof(u64));
|
|
+ const u8 left = len & (sizeof(u64) - 1);
|
|
+ u64 m;
|
|
+ PREAMBLE(len)
|
|
+ for (; data != end; data += sizeof(u64)) {
|
|
+ m = le64_to_cpup(data);
|
|
+ v3 ^= m;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= m;
|
|
+ }
|
|
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
|
|
+ if (left)
|
|
+ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
|
|
+ bytemask_from_count(left)));
|
|
+#else
|
|
+ switch (left) {
|
|
+ case 7: b |= ((u64)end[6]) << 48;
|
|
+ case 6: b |= ((u64)end[5]) << 40;
|
|
+ case 5: b |= ((u64)end[4]) << 32;
|
|
+ case 4: b |= le32_to_cpup(data); break;
|
|
+ case 3: b |= ((u64)end[2]) << 16;
|
|
+ case 2: b |= le16_to_cpup(data); break;
|
|
+ case 1: b |= end[0];
|
|
+ }
|
|
+#endif
|
|
+ POSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(__siphash_aligned);
|
|
+
|
|
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
|
+u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key)
|
|
+{
|
|
+ const u8 *end = data + len - (len % sizeof(u64));
|
|
+ const u8 left = len & (sizeof(u64) - 1);
|
|
+ u64 m;
|
|
+ PREAMBLE(len)
|
|
+ for (; data != end; data += sizeof(u64)) {
|
|
+ m = get_unaligned_le64(data);
|
|
+ v3 ^= m;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= m;
|
|
+ }
|
|
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
|
|
+ if (left)
|
|
+ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
|
|
+ bytemask_from_count(left)));
|
|
+#else
|
|
+ switch (left) {
|
|
+ case 7: b |= ((u64)end[6]) << 48;
|
|
+ case 6: b |= ((u64)end[5]) << 40;
|
|
+ case 5: b |= ((u64)end[4]) << 32;
|
|
+ case 4: b |= get_unaligned_le32(end); break;
|
|
+ case 3: b |= ((u64)end[2]) << 16;
|
|
+ case 2: b |= get_unaligned_le16(end); break;
|
|
+ case 1: b |= end[0];
|
|
+ }
|
|
+#endif
|
|
+ POSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(__siphash_unaligned);
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * siphash_1u64 - compute 64-bit siphash PRF value of a u64
|
|
+ * @first: first u64
|
|
+ * @key: the siphash key
|
|
+ */
|
|
+u64 siphash_1u64(const u64 first, const siphash_key_t *key)
|
|
+{
|
|
+ PREAMBLE(8)
|
|
+ v3 ^= first;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= first;
|
|
+ POSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(siphash_1u64);
|
|
+
|
|
+/**
|
|
+ * siphash_2u64 - compute 64-bit siphash PRF value of 2 u64
|
|
+ * @first: first u64
|
|
+ * @second: second u64
|
|
+ * @key: the siphash key
|
|
+ */
|
|
+u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key)
|
|
+{
|
|
+ PREAMBLE(16)
|
|
+ v3 ^= first;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= first;
|
|
+ v3 ^= second;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= second;
|
|
+ POSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(siphash_2u64);
|
|
+
|
|
+/**
|
|
+ * siphash_3u64 - compute 64-bit siphash PRF value of 3 u64
|
|
+ * @first: first u64
|
|
+ * @second: second u64
|
|
+ * @third: third u64
|
|
+ * @key: the siphash key
|
|
+ */
|
|
+u64 siphash_3u64(const u64 first, const u64 second, const u64 third,
|
|
+ const siphash_key_t *key)
|
|
+{
|
|
+ PREAMBLE(24)
|
|
+ v3 ^= first;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= first;
|
|
+ v3 ^= second;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= second;
|
|
+ v3 ^= third;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= third;
|
|
+ POSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(siphash_3u64);
|
|
+
|
|
+/**
|
|
+ * siphash_4u64 - compute 64-bit siphash PRF value of 4 u64
|
|
+ * @first: first u64
|
|
+ * @second: second u64
|
|
+ * @third: third u64
|
|
+ * @forth: forth u64
|
|
+ * @key: the siphash key
|
|
+ */
|
|
+u64 siphash_4u64(const u64 first, const u64 second, const u64 third,
|
|
+ const u64 forth, const siphash_key_t *key)
|
|
+{
|
|
+ PREAMBLE(32)
|
|
+ v3 ^= first;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= first;
|
|
+ v3 ^= second;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= second;
|
|
+ v3 ^= third;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= third;
|
|
+ v3 ^= forth;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= forth;
|
|
+ POSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(siphash_4u64);
|
|
+
|
|
+u64 siphash_1u32(const u32 first, const siphash_key_t *key)
|
|
+{
|
|
+ PREAMBLE(4)
|
|
+ b |= first;
|
|
+ POSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(siphash_1u32);
|
|
+
|
|
+u64 siphash_3u32(const u32 first, const u32 second, const u32 third,
|
|
+ const siphash_key_t *key)
|
|
+{
|
|
+ u64 combined = (u64)second << 32 | first;
|
|
+ PREAMBLE(12)
|
|
+ v3 ^= combined;
|
|
+ SIPROUND;
|
|
+ SIPROUND;
|
|
+ v0 ^= combined;
|
|
+ b |= third;
|
|
+ POSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(siphash_3u32);
|
|
+
|
|
+#if BITS_PER_LONG == 64
|
|
+/* Note that on 64-bit, we make HalfSipHash1-3 actually be SipHash1-3, for
|
|
+ * performance reasons. On 32-bit, below, we actually implement HalfSipHash1-3.
|
|
+ */
|
|
+
|
|
+#define HSIPROUND SIPROUND
|
|
+#define HPREAMBLE(len) PREAMBLE(len)
|
|
+#define HPOSTAMBLE \
|
|
+ v3 ^= b; \
|
|
+ HSIPROUND; \
|
|
+ v0 ^= b; \
|
|
+ v2 ^= 0xff; \
|
|
+ HSIPROUND; \
|
|
+ HSIPROUND; \
|
|
+ HSIPROUND; \
|
|
+ return (v0 ^ v1) ^ (v2 ^ v3);
|
|
+
|
|
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
|
|
+{
|
|
+ const u8 *end = data + len - (len % sizeof(u64));
|
|
+ const u8 left = len & (sizeof(u64) - 1);
|
|
+ u64 m;
|
|
+ HPREAMBLE(len)
|
|
+ for (; data != end; data += sizeof(u64)) {
|
|
+ m = le64_to_cpup(data);
|
|
+ v3 ^= m;
|
|
+ HSIPROUND;
|
|
+ v0 ^= m;
|
|
+ }
|
|
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
|
|
+ if (left)
|
|
+ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
|
|
+ bytemask_from_count(left)));
|
|
+#else
|
|
+ switch (left) {
|
|
+ case 7: b |= ((u64)end[6]) << 48;
|
|
+ case 6: b |= ((u64)end[5]) << 40;
|
|
+ case 5: b |= ((u64)end[4]) << 32;
|
|
+ case 4: b |= le32_to_cpup(data); break;
|
|
+ case 3: b |= ((u64)end[2]) << 16;
|
|
+ case 2: b |= le16_to_cpup(data); break;
|
|
+ case 1: b |= end[0];
|
|
+ }
|
|
+#endif
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(__hsiphash_aligned);
|
|
+
|
|
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
|
+u32 __hsiphash_unaligned(const void *data, size_t len,
|
|
+ const hsiphash_key_t *key)
|
|
+{
|
|
+ const u8 *end = data + len - (len % sizeof(u64));
|
|
+ const u8 left = len & (sizeof(u64) - 1);
|
|
+ u64 m;
|
|
+ HPREAMBLE(len)
|
|
+ for (; data != end; data += sizeof(u64)) {
|
|
+ m = get_unaligned_le64(data);
|
|
+ v3 ^= m;
|
|
+ HSIPROUND;
|
|
+ v0 ^= m;
|
|
+ }
|
|
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
|
|
+ if (left)
|
|
+ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
|
|
+ bytemask_from_count(left)));
|
|
+#else
|
|
+ switch (left) {
|
|
+ case 7: b |= ((u64)end[6]) << 48;
|
|
+ case 6: b |= ((u64)end[5]) << 40;
|
|
+ case 5: b |= ((u64)end[4]) << 32;
|
|
+ case 4: b |= get_unaligned_le32(end); break;
|
|
+ case 3: b |= ((u64)end[2]) << 16;
|
|
+ case 2: b |= get_unaligned_le16(end); break;
|
|
+ case 1: b |= end[0];
|
|
+ }
|
|
+#endif
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(__hsiphash_unaligned);
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32
|
|
+ * @first: first u32
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key)
|
|
+{
|
|
+ HPREAMBLE(4)
|
|
+ b |= first;
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(hsiphash_1u32);
|
|
+
|
|
+/**
|
|
+ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
|
|
+ * @first: first u32
|
|
+ * @second: second u32
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key)
|
|
+{
|
|
+ u64 combined = (u64)second << 32 | first;
|
|
+ HPREAMBLE(8)
|
|
+ v3 ^= combined;
|
|
+ HSIPROUND;
|
|
+ v0 ^= combined;
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(hsiphash_2u32);
|
|
+
|
|
+/**
|
|
+ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
|
|
+ * @first: first u32
|
|
+ * @second: second u32
|
|
+ * @third: third u32
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
|
|
+ const hsiphash_key_t *key)
|
|
+{
|
|
+ u64 combined = (u64)second << 32 | first;
|
|
+ HPREAMBLE(12)
|
|
+ v3 ^= combined;
|
|
+ HSIPROUND;
|
|
+ v0 ^= combined;
|
|
+ b |= third;
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(hsiphash_3u32);
|
|
+
|
|
+/**
|
|
+ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
|
|
+ * @first: first u32
|
|
+ * @second: second u32
|
|
+ * @third: third u32
|
|
+ * @forth: forth u32
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
|
|
+ const u32 forth, const hsiphash_key_t *key)
|
|
+{
|
|
+ u64 combined = (u64)second << 32 | first;
|
|
+ HPREAMBLE(16)
|
|
+ v3 ^= combined;
|
|
+ HSIPROUND;
|
|
+ v0 ^= combined;
|
|
+ combined = (u64)forth << 32 | third;
|
|
+ v3 ^= combined;
|
|
+ HSIPROUND;
|
|
+ v0 ^= combined;
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(hsiphash_4u32);
|
|
+#else
|
|
+#define HSIPROUND \
|
|
+ do { \
|
|
+ v0 += v1; v1 = rol32(v1, 5); v1 ^= v0; v0 = rol32(v0, 16); \
|
|
+ v2 += v3; v3 = rol32(v3, 8); v3 ^= v2; \
|
|
+ v0 += v3; v3 = rol32(v3, 7); v3 ^= v0; \
|
|
+ v2 += v1; v1 = rol32(v1, 13); v1 ^= v2; v2 = rol32(v2, 16); \
|
|
+ } while (0)
|
|
+
|
|
+#define HPREAMBLE(len) \
|
|
+ u32 v0 = 0; \
|
|
+ u32 v1 = 0; \
|
|
+ u32 v2 = 0x6c796765U; \
|
|
+ u32 v3 = 0x74656462U; \
|
|
+ u32 b = ((u32)(len)) << 24; \
|
|
+ v3 ^= key->key[1]; \
|
|
+ v2 ^= key->key[0]; \
|
|
+ v1 ^= key->key[1]; \
|
|
+ v0 ^= key->key[0];
|
|
+
|
|
+#define HPOSTAMBLE \
|
|
+ v3 ^= b; \
|
|
+ HSIPROUND; \
|
|
+ v0 ^= b; \
|
|
+ v2 ^= 0xff; \
|
|
+ HSIPROUND; \
|
|
+ HSIPROUND; \
|
|
+ HSIPROUND; \
|
|
+ return v1 ^ v3;
|
|
+
|
|
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
|
|
+{
|
|
+ const u8 *end = data + len - (len % sizeof(u32));
|
|
+ const u8 left = len & (sizeof(u32) - 1);
|
|
+ u32 m;
|
|
+ HPREAMBLE(len)
|
|
+ for (; data != end; data += sizeof(u32)) {
|
|
+ m = le32_to_cpup(data);
|
|
+ v3 ^= m;
|
|
+ HSIPROUND;
|
|
+ v0 ^= m;
|
|
+ }
|
|
+ switch (left) {
|
|
+ case 3: b |= ((u32)end[2]) << 16;
|
|
+ case 2: b |= le16_to_cpup(data); break;
|
|
+ case 1: b |= end[0];
|
|
+ }
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(__hsiphash_aligned);
|
|
+
|
|
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
|
+u32 __hsiphash_unaligned(const void *data, size_t len,
|
|
+ const hsiphash_key_t *key)
|
|
+{
|
|
+ const u8 *end = data + len - (len % sizeof(u32));
|
|
+ const u8 left = len & (sizeof(u32) - 1);
|
|
+ u32 m;
|
|
+ HPREAMBLE(len)
|
|
+ for (; data != end; data += sizeof(u32)) {
|
|
+ m = get_unaligned_le32(data);
|
|
+ v3 ^= m;
|
|
+ HSIPROUND;
|
|
+ v0 ^= m;
|
|
+ }
|
|
+ switch (left) {
|
|
+ case 3: b |= ((u32)end[2]) << 16;
|
|
+ case 2: b |= get_unaligned_le16(end); break;
|
|
+ case 1: b |= end[0];
|
|
+ }
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(__hsiphash_unaligned);
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32
|
|
+ * @first: first u32
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key)
|
|
+{
|
|
+ HPREAMBLE(4)
|
|
+ v3 ^= first;
|
|
+ HSIPROUND;
|
|
+ v0 ^= first;
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(hsiphash_1u32);
|
|
+
|
|
+/**
|
|
+ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
|
|
+ * @first: first u32
|
|
+ * @second: second u32
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key)
|
|
+{
|
|
+ HPREAMBLE(8)
|
|
+ v3 ^= first;
|
|
+ HSIPROUND;
|
|
+ v0 ^= first;
|
|
+ v3 ^= second;
|
|
+ HSIPROUND;
|
|
+ v0 ^= second;
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(hsiphash_2u32);
|
|
+
|
|
+/**
|
|
+ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
|
|
+ * @first: first u32
|
|
+ * @second: second u32
|
|
+ * @third: third u32
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
|
|
+ const hsiphash_key_t *key)
|
|
+{
|
|
+ HPREAMBLE(12)
|
|
+ v3 ^= first;
|
|
+ HSIPROUND;
|
|
+ v0 ^= first;
|
|
+ v3 ^= second;
|
|
+ HSIPROUND;
|
|
+ v0 ^= second;
|
|
+ v3 ^= third;
|
|
+ HSIPROUND;
|
|
+ v0 ^= third;
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(hsiphash_3u32);
|
|
+
|
|
+/**
|
|
+ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
|
|
+ * @first: first u32
|
|
+ * @second: second u32
|
|
+ * @third: third u32
|
|
+ * @forth: forth u32
|
|
+ * @key: the hsiphash key
|
|
+ */
|
|
+u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
|
|
+ const u32 forth, const hsiphash_key_t *key)
|
|
+{
|
|
+ HPREAMBLE(16)
|
|
+ v3 ^= first;
|
|
+ HSIPROUND;
|
|
+ v0 ^= first;
|
|
+ v3 ^= second;
|
|
+ HSIPROUND;
|
|
+ v0 ^= second;
|
|
+ v3 ^= third;
|
|
+ HSIPROUND;
|
|
+ v0 ^= third;
|
|
+ v3 ^= forth;
|
|
+ HSIPROUND;
|
|
+ v0 ^= forth;
|
|
+ HPOSTAMBLE
|
|
+}
|
|
+EXPORT_SYMBOL(hsiphash_4u32);
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/compat/compat.h
|
|
@@ -0,0 +1,198 @@
|
|
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
|
+
|
|
+#ifndef COMPAT_H
|
|
+#define COMPAT_H
|
|
+
|
|
+#include <linux/kconfig.h>
|
|
+#include <linux/version.h>
|
|
+#include <linux/types.h>
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
|
|
+#error "WireGuard requires Linux >= 3.18"
|
|
+#endif
|
|
+
|
|
+/* These conditionals can't be enforced by an out of tree module very easily,
|
|
+ * so we stick them here in compat instead. */
|
|
+#if !IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT)
|
|
+#error "WireGuard requires CONFIG_NETFILTER_XT_MATCH_HASHLIMIT."
|
|
+#endif
|
|
+#if IS_ENABLED(CONFIG_IPV6) && !IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
|
|
+#error "WireGuard requires CONFIG_IP6_NF_IPTABLES when using CONFIG_IPV6."
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) && !defined(DEBUG) && defined(net_dbg_ratelimited)
|
|
+#undef net_dbg_ratelimited
|
|
+#define net_dbg_ratelimited(fmt, ...) do { if (0) no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
|
|
+#define RCU_LOCKDEP_WARN(cond, message) rcu_lockdep_assert(!(cond), message)
|
|
+#endif
|
|
+
|
|
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 6)) || LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 12)
|
|
+#define dev_recursion_level() 0
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
|
|
+#include <linux/if.h>
|
|
+#include <net/udp_tunnel.h>
|
|
+#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__; ret__ = udp_tunnel_xmit_skb((b)->sk_socket, a, c, d, e, f, g, h, i, j, k); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0)
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) udp_tunnel6_xmit_skb((b)->sk_socket, a, c, d, e, f, g, h, j, k);
|
|
+#endif
|
|
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
|
|
+#include <linux/if.h>
|
|
+#include <net/udp_tunnel.h>
|
|
+static inline void fake_destructor(struct sk_buff *skb)
|
|
+{
|
|
+}
|
|
+#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__; (c)->destructor = fake_destructor; (c)->sk = (b); ret__ = udp_tunnel_xmit_skb(a, c, d, e, f, g, h, i, j, k, l); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0)
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { (c)->destructor = fake_destructor; (c)->sk = (b); udp_tunnel6_xmit_skb(a, c, d, e, f, g, h, j, k, l); } while(0)
|
|
+#endif
|
|
+#else
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
|
|
+#include <linux/if.h>
|
|
+#include <net/udp_tunnel.h>
|
|
+#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__ = udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0)
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) && IS_ENABLED(CONFIG_IPV6)
|
|
+#include <linux/if.h>
|
|
+#include <net/udp_tunnel.h>
|
|
+#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, j, k, l)
|
|
+#endif
|
|
+
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
|
|
+#include <linux/if.h>
|
|
+#include <net/udp_tunnel.h>
|
|
+struct udp_port_cfg_new {
|
|
+ u8 family;
|
|
+ union {
|
|
+ struct in_addr local_ip;
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ struct in6_addr local_ip6;
|
|
+#endif
|
|
+ };
|
|
+ union {
|
|
+ struct in_addr peer_ip;
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ struct in6_addr peer_ip6;
|
|
+#endif
|
|
+ };
|
|
+ __be16 local_udp_port;
|
|
+ __be16 peer_udp_port;
|
|
+ unsigned int use_udp_checksums:1, use_udp6_tx_checksums:1, use_udp6_rx_checksums:1, ipv6_v6only:1;
|
|
+};
|
|
+static inline int __maybe_unused udp_sock_create_new(struct net *net, struct udp_port_cfg_new *cfg, struct socket **sockp)
|
|
+{
|
|
+ struct udp_port_cfg old_cfg = {
|
|
+ .family = cfg->family,
|
|
+ .local_ip = cfg->local_ip,
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ .local_ip6 = cfg->local_ip6,
|
|
+#endif
|
|
+ .peer_ip = cfg->peer_ip,
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ .peer_ip6 = cfg->peer_ip6,
|
|
+#endif
|
|
+ .local_udp_port = cfg->local_udp_port,
|
|
+ .peer_udp_port = cfg->peer_udp_port,
|
|
+ .use_udp_checksums = cfg->use_udp_checksums,
|
|
+ .use_udp6_tx_checksums = cfg->use_udp6_tx_checksums,
|
|
+ .use_udp6_rx_checksums = cfg->use_udp6_rx_checksums
|
|
+ };
|
|
+ if (cfg->family == AF_INET)
|
|
+ return udp_sock_create4(net, &old_cfg, sockp);
|
|
+
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+ if (cfg->family == AF_INET6) {
|
|
+ int ret;
|
|
+ int old_bindv6only;
|
|
+ struct net *nobns;
|
|
+
|
|
+ if (cfg->ipv6_v6only) {
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
|
|
+ nobns = &init_net;
|
|
+#else
|
|
+ nobns = net;
|
|
+#endif
|
|
+ /* Since udp_port_cfg only learned of ipv6_v6only in 4.3, we do this horrible
|
|
+ * hack here and set the sysctl variable temporarily to something that will
|
|
+ * set the right option for us in sock_create. It's super racey! */
|
|
+ old_bindv6only = nobns->ipv6.sysctl.bindv6only;
|
|
+ nobns->ipv6.sysctl.bindv6only = 1;
|
|
+ }
|
|
+ ret = udp_sock_create6(net, &old_cfg, sockp);
|
|
+ if (cfg->ipv6_v6only)
|
|
+ nobns->ipv6.sysctl.bindv6only = old_bindv6only;
|
|
+ return ret;
|
|
+ }
|
|
+#endif
|
|
+ return -EPFNOSUPPORT;
|
|
+}
|
|
+#define udp_port_cfg udp_port_cfg_new
|
|
+#define udp_sock_create(a, b, c) udp_sock_create_new(a, b, c)
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
|
|
+#define ipv6_dst_lookup(a, b, c, d) ipv6_dst_lookup(b, c, d)
|
|
+#endif
|
|
+
|
|
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 5) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 17) && LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) || LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 27)
|
|
+#define IP6_ECN_set_ce(a, b) IP6_ECN_set_ce(b)
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
|
|
+#define time_is_before_jiffies64(a) time_after64(get_jiffies_64(), a)
|
|
+#define time_is_after_jiffies64(a) time_before64(get_jiffies_64(), a)
|
|
+#define time_is_before_eq_jiffies64(a) time_after_eq64(get_jiffies_64(), a)
|
|
+#define time_is_after_eq_jiffies64(a) time_before_eq64(get_jiffies_64(), a)
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) && IS_ENABLED(CONFIG_IPV6)
|
|
+#include <net/addrconf.h>
|
|
+static inline bool ipv6_mod_enabled(void)
|
|
+{
|
|
+ return ipv6_stub->udpv6_encap_enable != NULL;
|
|
+}
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
|
+#include <linux/skbuff.h>
|
|
+static inline void skb_reset_tc(struct sk_buff *skb)
|
|
+{
|
|
+#ifdef CONFIG_NET_CLS_ACT
|
|
+ skb->tc_verd = 0;
|
|
+#endif
|
|
+}
|
|
+#endif
|
|
+
|
|
+/* https://lkml.org/lkml/2015/6/12/415 */
|
|
+#include <linux/netdevice.h>
|
|
+static inline struct net_device *netdev_pub(void *dev)
|
|
+{
|
|
+ return (struct net_device *)((char *)dev - ALIGN(sizeof(struct net_device), NETDEV_ALIGN));
|
|
+}
|
|
+
|
|
+/* PaX compatibility */
|
|
+#ifdef CONSTIFY_PLUGIN
|
|
+#include <linux/cache.h>
|
|
+#undef __read_mostly
|
|
+#define __read_mostly
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
|
|
+#define net_dbg_skb_ratelimited(fmt, skb, ...) do { \
|
|
+ struct endpoint __endpoint; \
|
|
+ socket_endpoint_from_skb(&__endpoint, skb); \
|
|
+ net_dbg_ratelimited(fmt, &__endpoint.addr, ##__VA_ARGS__); \
|
|
+} while(0)
|
|
+#else
|
|
+#define net_dbg_skb_ratelimited(fmt, skb, ...)
|
|
+#endif
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/net/wireguard/compat/dst_cache/dst_cache.c
|
|
@@ -0,0 +1,177 @@
|
|
+/*
|
|
+ * net/core/dst_cache.c - dst entry cache
|
|
+ *
|
|
+ * Copyright (c) 2016 Paolo Abeni <pabeni@redhat.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/percpu.h>
|
|
+#include <net/dst_cache.h>
|
|
+#include <net/route.h>
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+#include <net/ip6_fib.h>
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
|
|
+static inline u32 rt6_get_cookie(const struct rt6_info *rt)
|
|
+{
|
|
+ if ((unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from))
|
|
+ rt = (struct rt6_info *)(rt->dst.from);
|
|
+
|
|
+ return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
|
|
+}
|
|
+#endif
|
|
+#endif
|
|
+#include <uapi/linux/in.h>
|
|
+
|
|
+struct dst_cache_pcpu {
|
|
+ unsigned long refresh_ts;
|
|
+ struct dst_entry *dst;
|
|
+ u32 cookie;
|
|
+ union {
|
|
+ struct in_addr in_saddr;
|
|
+ struct in6_addr in6_saddr;
|
|
+ };
|
|
+};
|
|
+
|
|
+static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,
|
|
+ struct dst_entry *dst, u32 cookie)
|
|
+{
|
|
+ dst_release(dst_cache->dst);
|
|
+ if (dst)
|
|
+ dst_hold(dst);
|
|
+
|
|
+ dst_cache->cookie = cookie;
|
|
+ dst_cache->dst = dst;
|
|
+}
|
|
+
|
|
+static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
|
|
+ struct dst_cache_pcpu *idst)
|
|
+{
|
|
+ struct dst_entry *dst;
|
|
+
|
|
+ dst = idst->dst;
|
|
+ if (!dst)
|
|
+ goto fail;
|
|
+
|
|
+ /* the cache already hold a dst reference; it can't go away */
|
|
+ dst_hold(dst);
|
|
+
|
|
+ if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) ||
|
|
+ (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) {
|
|
+ dst_cache_per_cpu_dst_set(idst, NULL, 0);
|
|
+ dst_release(dst);
|
|
+ goto fail;
|
|
+ }
|
|
+ return dst;
|
|
+
|
|
+fail:
|
|
+ idst->refresh_ts = jiffies;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct dst_entry *dst_cache_get(struct dst_cache *dst_cache)
|
|
+{
|
|
+ if (!dst_cache->cache)
|
|
+ return NULL;
|
|
+
|
|
+ return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache));
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(dst_cache_get);
|
|
+
|
|
+struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr)
|
|
+{
|
|
+ struct dst_cache_pcpu *idst;
|
|
+ struct dst_entry *dst;
|
|
+
|
|
+ if (!dst_cache->cache)
|
|
+ return NULL;
|
|
+
|
|
+ idst = this_cpu_ptr(dst_cache->cache);
|
|
+ dst = dst_cache_per_cpu_get(dst_cache, idst);
|
|
+ if (!dst)
|
|
+ return NULL;
|
|
+
|
|
+ *saddr = idst->in_saddr.s_addr;
|
|
+ return container_of(dst, struct rtable, dst);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(dst_cache_get_ip4);
|
|
+
|
|
+void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
|
|
+ __be32 saddr)
|
|
+{
|
|
+ struct dst_cache_pcpu *idst;
|
|
+
|
|
+ if (!dst_cache->cache)
|
|
+ return;
|
|
+
|
|
+ idst = this_cpu_ptr(dst_cache->cache);
|
|
+ dst_cache_per_cpu_dst_set(idst, dst, 0);
|
|
+ idst->in_saddr.s_addr = saddr;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(dst_cache_set_ip4);
|
|
+
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
|
|
+ const struct in6_addr *addr)
|
|
+{
|
|
+ struct dst_cache_pcpu *idst;
|
|
+
|
|
+ if (!dst_cache->cache)
|
|
+ return;
|
|
+
|
|
+ idst = this_cpu_ptr(dst_cache->cache);
|
|
+ dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst,
|
|
+ rt6_get_cookie((struct rt6_info *)dst));
|
|
+ idst->in6_saddr = *addr;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(dst_cache_set_ip6);
|
|
+
|
|
+struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
|
|
+ struct in6_addr *saddr)
|
|
+{
|
|
+ struct dst_cache_pcpu *idst;
|
|
+ struct dst_entry *dst;
|
|
+
|
|
+ if (!dst_cache->cache)
|
|
+ return NULL;
|
|
+
|
|
+ idst = this_cpu_ptr(dst_cache->cache);
|
|
+ dst = dst_cache_per_cpu_get(dst_cache, idst);
|
|
+ if (!dst)
|
|
+ return NULL;
|
|
+
|
|
+ *saddr = idst->in6_saddr;
|
|
+ return dst;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(dst_cache_get_ip6);
|
|
+#endif
|
|
+
|
|
+int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp)
|
|
+{
|
|
+ dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu,
|
|
+ gfp | __GFP_ZERO);
|
|
+ if (!dst_cache->cache)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ dst_cache_reset(dst_cache);
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(dst_cache_init);
|
|
+
|
|
+void dst_cache_destroy(struct dst_cache *dst_cache)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (!dst_cache->cache)
|
|
+ return;
|
|
+
|
|
+ for_each_possible_cpu(i)
|
|
+ dst_release(per_cpu_ptr(dst_cache->cache, i)->dst);
|
|
+
|
|
+ free_percpu(dst_cache->cache);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(dst_cache_destroy);
|
|
--- /dev/null
|
|
+++ b/net/wireguard/compat/dst_cache/include/net/dst_cache.h
|
|
@@ -0,0 +1,97 @@
|
|
+#ifndef _NET_DST_CACHE_H
|
|
+#define _NET_DST_CACHE_H
|
|
+
|
|
+#include <linux/jiffies.h>
|
|
+#include <net/dst.h>
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+#include <net/ip6_fib.h>
|
|
+#endif
|
|
+
|
|
+struct dst_cache {
|
|
+ struct dst_cache_pcpu __percpu *cache;
|
|
+ unsigned long reset_ts;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * dst_cache_get - perform cache lookup
|
|
+ * @dst_cache: the cache
|
|
+ *
|
|
+ * The caller should use dst_cache_get_ip4() if it need to retrieve the
|
|
+ * source address to be used when xmitting to the cached dst.
|
|
+ * local BH must be disabled.
|
|
+ */
|
|
+struct dst_entry *dst_cache_get(struct dst_cache *dst_cache);
|
|
+
|
|
+/**
|
|
+ * dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address
|
|
+ * @dst_cache: the cache
|
|
+ * @saddr: return value for the retrieved source address
|
|
+ *
|
|
+ * local BH must be disabled.
|
|
+ */
|
|
+struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr);
|
|
+
|
|
+/**
|
|
+ * dst_cache_set_ip4 - store the ipv4 dst into the cache
|
|
+ * @dst_cache: the cache
|
|
+ * @dst: the entry to be cached
|
|
+ * @saddr: the source address to be stored inside the cache
|
|
+ *
|
|
+ * local BH must be disabled.
|
|
+ */
|
|
+void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
|
|
+ __be32 saddr);
|
|
+
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
+
|
|
+/**
|
|
+ * dst_cache_set_ip6 - store the ipv6 dst into the cache
|
|
+ * @dst_cache: the cache
|
|
+ * @dst: the entry to be cached
|
|
+ * @saddr: the source address to be stored inside the cache
|
|
+ *
|
|
+ * local BH must be disabled.
|
|
+ */
|
|
+void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
|
|
+ const struct in6_addr *addr);
|
|
+
|
|
+/**
|
|
+ * dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address
|
|
+ * @dst_cache: the cache
|
|
+ * @saddr: return value for the retrieved source address
|
|
+ *
|
|
+ * local BH must be disabled.
|
|
+ */
|
|
+struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
|
|
+ struct in6_addr *saddr);
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * dst_cache_reset - invalidate the cache contents
|
|
+ * @dst_cache: the cache
|
|
+ *
|
|
+ * This do not free the cached dst to avoid races and contentions.
|
|
+ * the dst will be freed on later cache lookup.
|
|
+ */
|
|
+static inline void dst_cache_reset(struct dst_cache *dst_cache)
|
|
+{
|
|
+ dst_cache->reset_ts = jiffies;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * dst_cache_init - initialize the cache, allocating the required storage
|
|
+ * @dst_cache: the cache
|
|
+ * @gfp: allocation flags
|
|
+ */
|
|
+int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp);
|
|
+
|
|
+/**
|
|
+ * dst_cache_destroy - empty the cache and free the allocated storage
|
|
+ * @dst_cache: the cache
|
|
+ *
|
|
+ * No synchronization is enforced: it must be called only when the cache
|
|
+ * is unsed.
|
|
+ */
|
|
+void dst_cache_destroy(struct dst_cache *dst_cache);
|
|
+
|
|
+#endif
|
|
--- a/net/Kconfig
|
|
+++ b/net/Kconfig
|
|
@@ -85,2 +85,3 @@ config INET
|
|
if INET
|
|
+source "net/wireguard/Kconfig"
|
|
source "net/ipv4/Kconfig"
|
|
--- a/net/Makefile
|
|
+++ b/net/Makefile
|
|
@@ -16,2 +16,3 @@
|
|
obj-$(CONFIG_NETFILTER) += netfilter/
|
|
+obj-$(CONFIG_WIREGUARD) += wireguard/
|
|
obj-$(CONFIG_INET) += ipv4/
|