Move, modify and add key generation functions to project.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jeroen Leenarts 2018-08-22 08:47:20 +02:00
parent 388e652315
commit 56362ebd68
7 changed files with 250 additions and 178 deletions

View File

@ -33,6 +33,8 @@
4A61D83520D98D25006C7A76 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A61D83420D98D25006C7A76 /* NetworkExtension.framework */; }; 4A61D83520D98D25006C7A76 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A61D83420D98D25006C7A76 /* NetworkExtension.framework */; };
4A8AABD820B6A79100B6D8C1 /* UITableView+WireGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A8AABD720B6A79100B6D8C1 /* UITableView+WireGuard.swift */; }; 4A8AABD820B6A79100B6D8C1 /* UITableView+WireGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A8AABD720B6A79100B6D8C1 /* UITableView+WireGuard.swift */; };
4AADEA2B212616F7008C24FD /* String+Arrays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA1D50F2124D80C00DBA2E6 /* String+Arrays.swift */; }; 4AADEA2B212616F7008C24FD /* String+Arrays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA1D50F2124D80C00DBA2E6 /* String+Arrays.swift */; };
4ABFFEA0212D39A000107136 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 4ABFFE9F212D39A000107136 /* x25519.c */; };
4ABFFEA3212D3C8300107136 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ABFFEA2212D3C8300107136 /* Security.framework */; };
4AC086832120B9F900CEE5ED /* ProviderConfigurationKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC086822120B9F900CEE5ED /* ProviderConfigurationKeys.swift */; }; 4AC086832120B9F900CEE5ED /* ProviderConfigurationKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC086822120B9F900CEE5ED /* ProviderConfigurationKeys.swift */; };
4AC086852120BCB500CEE5ED /* ProviderConfigurationKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC086822120B9F900CEE5ED /* ProviderConfigurationKeys.swift */; }; 4AC086852120BCB500CEE5ED /* ProviderConfigurationKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC086822120B9F900CEE5ED /* ProviderConfigurationKeys.swift */; };
4AC086862120BD5800CEE5ED /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A61D82820D98CE2006C7A76 /* PacketTunnelProvider.swift */; }; 4AC086862120BD5800CEE5ED /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A61D82820D98CE2006C7A76 /* PacketTunnelProvider.swift */; };
@ -115,6 +117,10 @@
4A61D83320D98D07006C7A76 /* WireGuard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuard.entitlements; sourceTree = "<group>"; }; 4A61D83320D98D07006C7A76 /* WireGuard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuard.entitlements; sourceTree = "<group>"; };
4A61D83420D98D25006C7A76 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; 4A61D83420D98D25006C7A76 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
4A8AABD720B6A79100B6D8C1 /* UITableView+WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+WireGuard.swift"; sourceTree = "<group>"; }; 4A8AABD720B6A79100B6D8C1 /* UITableView+WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+WireGuard.swift"; sourceTree = "<group>"; };
4ABFFE9D212D399F00107136 /* WireGuard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuard-Bridging-Header.h"; sourceTree = "<group>"; };
4ABFFE9E212D39A000107136 /* x25519.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x25519.h; sourceTree = "<group>"; };
4ABFFE9F212D39A000107136 /* x25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x25519.c; sourceTree = "<group>"; };
4ABFFEA2212D3C8300107136 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
4AC086822120B9F900CEE5ED /* ProviderConfigurationKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderConfigurationKeys.swift; sourceTree = "<group>"; }; 4AC086822120B9F900CEE5ED /* ProviderConfigurationKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderConfigurationKeys.swift; sourceTree = "<group>"; };
4AC5462D2116306F00749D21 /* Tunnel+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tunnel+Extension.swift"; sourceTree = "<group>"; }; 4AC5462D2116306F00749D21 /* Tunnel+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tunnel+Extension.swift"; sourceTree = "<group>"; };
4AD0900120DC4171000E9CF5 /* libwg-go.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libwg-go.a"; sourceTree = "<group>"; }; 4AD0900120DC4171000E9CF5 /* libwg-go.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libwg-go.a"; sourceTree = "<group>"; };
@ -138,6 +144,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
4ABFFEA3212D3C8300107136 /* Security.framework in Frameworks */,
48CF751B34E9703133F1B1AF /* Pods_WireGuard.framework in Frameworks */, 48CF751B34E9703133F1B1AF /* Pods_WireGuard.framework in Frameworks */,
4A61D83520D98D25006C7A76 /* NetworkExtension.framework in Frameworks */, 4A61D83520D98D25006C7A76 /* NetworkExtension.framework in Frameworks */,
); );
@ -190,6 +197,7 @@
4A4BACE420B5F1BF00F12B28 /* WireGuard */ = { 4A4BACE420B5F1BF00F12B28 /* WireGuard */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4ABFFEA1212D39CA00107136 /* Crypto */,
4A61D83320D98D07006C7A76 /* WireGuard.entitlements */, 4A61D83320D98D07006C7A76 /* WireGuard.entitlements */,
4A4BAD1420B5F8C000F12B28 /* Models */, 4A4BAD1420B5F8C000F12B28 /* Models */,
4A4BAD1120B5F7A000F12B28 /* ViewControllers */, 4A4BAD1120B5F7A000F12B28 /* ViewControllers */,
@ -200,6 +208,7 @@
4A4BACEC20B5F1C100F12B28 /* Assets.xcassets */, 4A4BACEC20B5F1C100F12B28 /* Assets.xcassets */,
4A4BACEE20B5F1C100F12B28 /* LaunchScreen.storyboard */, 4A4BACEE20B5F1C100F12B28 /* LaunchScreen.storyboard */,
4A4BACF120B5F1C100F12B28 /* Info.plist */, 4A4BACF120B5F1C100F12B28 /* Info.plist */,
4ABFFE9D212D399F00107136 /* WireGuard-Bridging-Header.h */,
4AEAC32A20F14BA9007B67AB /* Log.swift */, 4AEAC32A20F14BA9007B67AB /* Log.swift */,
); );
path = WireGuard; path = WireGuard;
@ -276,6 +285,15 @@
path = WireGuardNetworkExtension; path = WireGuardNetworkExtension;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
4ABFFEA1212D39CA00107136 /* Crypto */ = {
isa = PBXGroup;
children = (
4ABFFE9F212D39A000107136 /* x25519.c */,
4ABFFE9E212D39A000107136 /* x25519.h */,
);
path = Crypto;
sourceTree = "<group>";
};
4AC086812120B9E600CEE5ED /* Shared */ = { 4AC086812120B9E600CEE5ED /* Shared */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -315,6 +333,7 @@
A447093459F091F4358E843F /* Frameworks */ = { A447093459F091F4358E843F /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4ABFFEA2212D3C8300107136 /* Security.framework */,
4A61D83420D98D25006C7A76 /* NetworkExtension.framework */, 4A61D83420D98D25006C7A76 /* NetworkExtension.framework */,
861983CAE8FDC13BC83E7E04 /* Pods_WireGuard.framework */, 861983CAE8FDC13BC83E7E04 /* Pods_WireGuard.framework */,
); );
@ -566,6 +585,7 @@
4AC5462E2116306F00749D21 /* Tunnel+Extension.swift in Sources */, 4AC5462E2116306F00749D21 /* Tunnel+Extension.swift in Sources */,
5FCC4343212B3092009A9C58 /* QRScanViewController.swift in Sources */, 5FCC4343212B3092009A9C58 /* QRScanViewController.swift in Sources */,
4A4BAD0E20B5F6C300F12B28 /* Coordinator.swift in Sources */, 4A4BAD0E20B5F6C300F12B28 /* Coordinator.swift in Sources */,
4ABFFEA0212D39A000107136 /* x25519.c in Sources */,
4A4BA6D820B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift in Sources */, 4A4BA6D820B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift in Sources */,
4A4BAD2020B6026900F12B28 /* Peer+CoreDataProperties.swift in Sources */, 4A4BAD2020B6026900F12B28 /* Peer+CoreDataProperties.swift in Sources */,
5FA1D4CD2124A05C00DBA2E6 /* Interface+Extension.swift in Sources */, 5FA1D4CD2124A05C00DBA2E6 /* Interface+Extension.swift in Sources */,
@ -755,6 +775,7 @@
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = WireGuard/WireGuard.entitlements; CODE_SIGN_ENTITLEMENTS = WireGuard/WireGuard.entitlements;
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = 67JZJ7TWU3; DEVELOPMENT_TEAM = 67JZJ7TWU3;
@ -767,6 +788,8 @@
PRODUCT_BUNDLE_IDENTIFIER = com.wireguard.ios.WireGuard; PRODUCT_BUNDLE_IDENTIFIER = com.wireguard.ios.WireGuard;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "WireGuard/WireGuard-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0; SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
@ -778,6 +801,7 @@
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = WireGuard/WireGuard.entitlements; CODE_SIGN_ENTITLEMENTS = WireGuard/WireGuard.entitlements;
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
@ -790,6 +814,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.wireguard.ios.WireGuard; PRODUCT_BUNDLE_IDENTIFIER = com.wireguard.ios.WireGuard;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "WireGuard/WireGuard-Bridging-Header.h";
SWIFT_VERSION = 4.0; SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };

View File

@ -171,6 +171,9 @@
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="C1M-bh-5mf"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="C1M-bh-5mf">
<rect key="frame" x="240" y="0.0" width="103" height="35.5"/> <rect key="frame" x="240" y="0.0" width="103" height="35.5"/>
<state key="normal" title="Generate"/> <state key="normal" title="Generate"/>
<connections>
<action selector="generateTapped:" destination="06N-KU-LSv" eventType="touchUpInside" id="efE-zK-eCe"/>
</connections>
</button> </button>
</subviews> </subviews>
</stackView> </stackView>

177
WireGuard/Crypto/x25519.c Normal file
View File

@ -0,0 +1,177 @@
/* SPDX-License-Identifier: GPL-2.0+
*
* Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* Curve25519 ECDH functions, based on TweetNaCl but cleaned up.
*/
#include <stdint.h>
#include <string.h>
#include <CommonCrypto/CommonRandom.h>
#include "x25519.h"
typedef int64_t fe[16];
static inline void carry(fe o)
{
int i;
for (i = 0; i < 16; ++i) {
o[(i + 1) % 16] += (i == 15 ? 38 : 1) * (o[i] >> 16);
o[i] &= 0xffff;
}
}
static inline void cswap(fe p, fe q, int b)
{
int i;
int64_t t, c = ~(b - 1);
for (i = 0; i < 16; ++i) {
t = c & (p[i] ^ q[i]);
p[i] ^= t;
q[i] ^= t;
}
}
static inline void pack(uint8_t *o, const fe n)
{
int i, j, b;
fe m, t;
memcpy(t, n, sizeof(t));
carry(t);
carry(t);
carry(t);
for (j = 0; j < 2; ++j) {
m[0] = t[0] - 0xffed;
for (i = 1; i < 15; ++i) {
m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
m[i - 1] &= 0xffff;
}
m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
b = (m[15] >> 16) & 1;
m[14] &= 0xffff;
cswap(t, m, 1 - b);
}
for (i = 0; i < 16; ++i) {
o[2 * i] = t[i] & 0xff;
o[2 * i + 1] = t[i] >> 8;
}
}
static inline void unpack(fe o, const uint8_t *n)
{
int i;
for (i = 0; i < 16; ++i)
o[i] = n[2 * i] + ((int64_t)n[2 * i + 1] << 8);
o[15] &= 0x7fff;
}
static inline void add(fe o, const fe a, const fe b)
{
int i;
for (i = 0; i < 16; ++i)
o[i] = a[i] + b[i];
}
static inline void subtract(fe o, const fe a, const fe b)
{
int i;
for (i = 0; i < 16; ++i)
o[i] = a[i] - b[i];
}
static inline void multmod(fe o, const fe a, const fe b)
{
int i, j;
int64_t t[31] = { 0 };
for (i = 0; i < 16; ++i) {
for (j = 0; j < 16; ++j)
t[i + j] += a[i] * b[j];
}
for (i = 0; i < 15; ++i)
t[i] += 38 * t[i + 16];
memcpy(o, t, sizeof(fe));
carry(o);
carry(o);
}
static inline void invert(fe o, const fe i)
{
fe c;
int a;
memcpy(c, i, sizeof(c));
for (a = 253; a >= 0; --a) {
multmod(c, c, c);
if (a != 2 && a != 4)
multmod(c, c, i);
}
memcpy(o, c, sizeof(fe));
}
static void curve25519_shared_secret(uint8_t shared_secret[32], const uint8_t private_key[32], const uint8_t public_key[32])
{
static const fe a24 = { 0xdb41, 1 };
uint8_t z[32];
int64_t r;
int i;
fe a = { 1 }, b, c = { 0 }, d = { 1 }, e, f, x;
memcpy(z, private_key, sizeof(z));
z[31] = (z[31] & 127) | 64;
z[0] &= 248;
unpack(x, public_key);
memcpy(b, x, sizeof(b));
for (i = 254; i >= 0; --i) {
r = (z[i >> 3] >> (i & 7)) & 1;
cswap(a, b, r);
cswap(c, d, r);
add(e, a, c);
subtract(a, a, c);
add(c, b, d);
subtract(b, b, d);
multmod(d, e, e);
multmod(f, a, a);
multmod(a, c, a);
multmod(c, b, e);
add(e, a, c);
subtract(a, a, c);
multmod(b, a, a);
subtract(c, d, f);
multmod(a, c, a24);
add(a, a, d);
multmod(c, c, a);
multmod(a, d, f);
multmod(d, b, x);
multmod(b, e, e);
cswap(a, b, r);
cswap(c, d, r);
}
invert(c, c);
multmod(a, a, c);
pack(shared_secret, a);
}
void curve25519_derive_public_key(uint8_t public_key[32], const uint8_t private_key[32])
{
static const uint8_t basepoint[32] = { 9 };
curve25519_shared_secret(public_key, private_key, basepoint);
}
void curve25519_generate_private_key(uint8_t private_key[32])
{
CCRandomGenerateBytes(private_key, 32);
private_key[31] = (private_key[31] & 127) | 64;
private_key[0] &= 248;
}

View File

@ -79,6 +79,7 @@ class TunnelConfigurationTableViewController: UITableViewController {
case 0: case 0:
let cell = tableView.dequeueReusableCell(type: InterfaceTableViewCell.self, for: indexPath) let cell = tableView.dequeueReusableCell(type: InterfaceTableViewCell.self, for: indexPath)
cell.model = tunnel.interface cell.model = tunnel.interface
cell.delegate = self
return cell return cell
case 1: case 1:
let cell = tableView.dequeueReusableCell(type: PeerTableViewCell.self, for: indexPath) let cell = tableView.dequeueReusableCell(type: PeerTableViewCell.self, for: indexPath)
@ -141,6 +142,38 @@ extension TunnelConfigurationTableViewController: PeerTableViewCellDelegate {
} }
} }
extension TunnelConfigurationTableViewController: InterfaceTableViewCellDelegate {
func generateKeys() {
if let moc = tunnel.managedObjectContext {
moc.perform {
var privateKey = Data(count: 32)
privateKey.withUnsafeMutableBytes { (mutableBytes) -> Void in
curve25519_generate_private_key(mutableBytes)
}
self.tunnel.interface?.privateKey = privateKey.base64EncodedString()
if let peers = self.tunnel.peers?.array as? [Peer] {
peers.forEach {
var publicKey = Data(count: 32)
privateKey.withUnsafeBytes({ (privateKeyBytes) -> Void in
publicKey.withUnsafeMutableBytes({ (mutableBytes) -> Void in
curve25519_derive_public_key(mutableBytes, privateKeyBytes)
})
})
$0.publicKey = publicKey.base64EncodedString()
}
}
}
}
self.tableView.reloadData()
}
}
protocol InterfaceTableViewCellDelegate: class {
func generateKeys()
}
class InterfaceTableViewCell: UITableViewCell { class InterfaceTableViewCell: UITableViewCell {
var model: Interface! { var model: Interface! {
didSet { didSet {
@ -153,16 +186,22 @@ class InterfaceTableViewCell: UITableViewCell {
} }
} }
weak var delegate: InterfaceTableViewCellDelegate?
@IBOutlet weak var nameField: UITextField! @IBOutlet weak var nameField: UITextField!
@IBOutlet weak var addressesField: UITextField! @IBOutlet weak var addressesField: UITextField!
@IBOutlet weak var privateKeyField: UITextField! @IBOutlet weak var privateKeyField: UITextField!
@IBOutlet weak var publicKeyField: UITextField!
@IBOutlet weak var listenPortField: UITextField! @IBOutlet weak var listenPortField: UITextField!
@IBOutlet weak var dnsField: UITextField! @IBOutlet weak var dnsField: UITextField!
@IBOutlet weak var mtuField: UITextField! @IBOutlet weak var mtuField: UITextField!
@IBAction func generateTapped(_ sender: Any) {
delegate?.generateKeys()
}
} }
extension InterfaceTableViewCell: UITextFieldDelegate { extension InterfaceTableViewCell: UITextFieldDelegate {
@IBAction @IBAction
func textfieldDidChange(_ sender: UITextField) { func textfieldDidChange(_ sender: UITextField) {
let string = sender.text let string = sender.text

View File

@ -0,0 +1,5 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#include "x25519.h"

View File

@ -1,177 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0+
*
* Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* Curve25519 ECDH functions, based on TweetNaCl but cleaned up.
*/
#include <stdint.h>
#include <string.h>
#include <sys/random.h>
#include "x25519.h"
typedef int64_t fe[16];
static inline void carry(fe o)
{
int i;
for (i = 0; i < 16; ++i) {
o[(i + 1) % 16] += (i == 15 ? 38 : 1) * (o[i] >> 16);
o[i] &= 0xffff;
}
}
static inline void cswap(fe p, fe q, int b)
{
int i;
int64_t t, c = ~(b - 1);
for (i = 0; i < 16; ++i) {
t = c & (p[i] ^ q[i]);
p[i] ^= t;
q[i] ^= t;
}
}
static inline void pack(uint8_t *o, const fe n)
{
int i, j, b;
fe m, t;
memcpy(t, n, sizeof(t));
carry(t);
carry(t);
carry(t);
for (j = 0; j < 2; ++j) {
m[0] = t[0] - 0xffed;
for (i = 1; i < 15; ++i) {
m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
m[i - 1] &= 0xffff;
}
m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
b = (m[15] >> 16) & 1;
m[14] &= 0xffff;
cswap(t, m, 1 - b);
}
for (i = 0; i < 16; ++i) {
o[2 * i] = t[i] & 0xff;
o[2 * i + 1] = t[i] >> 8;
}
}
static inline void unpack(fe o, const uint8_t *n)
{
int i;
for (i = 0; i < 16; ++i)
o[i] = n[2 * i] + ((int64_t)n[2 * i + 1] << 8);
o[15] &= 0x7fff;
}
static inline void add(fe o, const fe a, const fe b)
{
int i;
for (i = 0; i < 16; ++i)
o[i] = a[i] + b[i];
}
static inline void subtract(fe o, const fe a, const fe b)
{
int i;
for (i = 0; i < 16; ++i)
o[i] = a[i] - b[i];
}
static inline void multmod(fe o, const fe a, const fe b)
{
int i, j;
int64_t t[31] = { 0 };
for (i = 0; i < 16; ++i) {
for (j = 0; j < 16; ++j)
t[i + j] += a[i] * b[j];
}
for (i = 0; i < 15; ++i)
t[i] += 38 * t[i + 16];
memcpy(o, t, sizeof(fe));
carry(o);
carry(o);
}
static inline void invert(fe o, const fe i)
{
fe c;
int a;
memcpy(c, i, sizeof(c));
for (a = 253; a >= 0; --a) {
multmod(c, c, c);
if (a != 2 && a != 4)
multmod(c, c, i);
}
memcpy(o, c, sizeof(fe));
}
static void curve25519_shared_secret(uint8_t shared_secret[32], const uint8_t private_key[32], const uint8_t public_key[32])
{
static const fe a24 = { 0xdb41, 1 };
uint8_t z[32];
int64_t r;
int i;
fe a = { 1 }, b, c = { 0 }, d = { 1 }, e, f, x;
memcpy(z, private_key, sizeof(z));
z[31] = (z[31] & 127) | 64;
z[0] &= 248;
unpack(x, public_key);
memcpy(b, x, sizeof(b));
for (i = 254; i >= 0; --i) {
r = (z[i >> 3] >> (i & 7)) & 1;
cswap(a, b, r);
cswap(c, d, r);
add(e, a, c);
subtract(a, a, c);
add(c, b, d);
subtract(b, b, d);
multmod(d, e, e);
multmod(f, a, a);
multmod(a, c, a);
multmod(c, b, e);
add(e, a, c);
subtract(a, a, c);
multmod(b, a, a);
subtract(c, d, f);
multmod(a, c, a24);
add(a, a, d);
multmod(c, c, a);
multmod(a, d, f);
multmod(d, b, x);
multmod(b, e, e);
cswap(a, b, r);
cswap(c, d, r);
}
invert(c, c);
multmod(a, a, c);
pack(shared_secret, a);
}
void curve25519_derive_public_key(uint8_t public_key[32], const uint8_t private_key[32])
{
static const uint8_t basepoint[32] = { 9 };
curve25519_shared_secret(public_key, private_key, basepoint);
}
void curve25519_generate_private_key(uint8_t private_key[32])
{
getentropy(private_key, 32);
private_key[31] = (private_key[31] & 127) | 64;
private_key[0] &= 248;
}