summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2018-02-12 20:44:36 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2018-02-13 19:47:31 +0100
commitd1c863b16e34526e9600b3a3e1c6d4fd9ba3bd46 (patch)
treed21651d53c246ef78618cfde6425ce557448c0e3
parentb22e2b259bc0e6287bbcdec4a13bb84689d1c08f (diff)
KeyEncoding: add constant time hex implementation
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--app/src/main/java/com/wireguard/crypto/KeyEncoding.java46
1 files changed, 44 insertions, 2 deletions
diff --git a/app/src/main/java/com/wireguard/crypto/KeyEncoding.java b/app/src/main/java/com/wireguard/crypto/KeyEncoding.java
index 99ff0ee9..92e03230 100644
--- a/app/src/main/java/com/wireguard/crypto/KeyEncoding.java
+++ b/app/src/main/java/com/wireguard/crypto/KeyEncoding.java
@@ -3,15 +3,20 @@
package com.wireguard.crypto;
/**
- * This is a specialized constant-time base64 implementation that resists side-channel attacks.
+ * This is a specialized constant-time base64 and hex implementation that resists side-channel attacks.
*/
@SuppressWarnings("MagicNumber")
public final class KeyEncoding {
public static final int KEY_LENGTH = 32;
public static final int KEY_LENGTH_BASE64 = 44;
+ public static final int KEY_LENGTH_HEX = 64;
private static final String KEY_LENGTH_BASE64_EXCEPTION_MESSAGE =
"WireGuard base64 keys must be 44 characters encoding 32 bytes";
+ private static final String KEY_LENGTH_HEX_EXCEPTION_MESSAGE =
+ "WireGuard hex keys must be 64 characters encoding 32 bytes";
+ private static final String KEY_LENGTH_EXCEPTION_MESSAGE =
+ "WireGuard keys must be 32 bytes";
private KeyEncoding() {
// Prevent instantiation.
@@ -80,7 +85,7 @@ public final class KeyEncoding {
public static String keyToBase64(final byte[] key) {
final char[] output = new char[KEY_LENGTH_BASE64];
if (key.length != KEY_LENGTH)
- throw new IllegalArgumentException("WireGuard keys must be 32 bytes");
+ throw new IllegalArgumentException(KEY_LENGTH_EXCEPTION_MESSAGE);
int i;
for (i = 0; i < KEY_LENGTH / 3; ++i)
encodeBase64(key, i * 3, output, i * 4);
@@ -93,4 +98,41 @@ public final class KeyEncoding {
output[KEY_LENGTH_BASE64 - 1] = '=';
return new String(output);
}
+
+ public static byte[] keyFromHex(final String str) {
+ final char[] input = str.toCharArray();
+ final byte[] key = new byte[KEY_LENGTH];
+ if (input.length != KEY_LENGTH_HEX)
+ throw new IllegalArgumentException(KEY_LENGTH_HEX_EXCEPTION_MESSAGE);
+
+ int c, c_acc = 0, c_alpha0, c_alpha, c_num0, c_num, c_val, state = 0;
+
+ for (int i = 0; i < KEY_LENGTH_HEX; ++i) {
+ c = input[i];
+ c_num = c ^ 48;
+ c_num0 = (c_num - 10) >>8;
+ c_alpha = (c & ~32) - 55;
+ c_alpha0 = ((c_alpha - 10) ^ (c_alpha - 16)) >> 8;
+ if ((c_num0 | c_alpha0) == 0)
+ throw new IllegalArgumentException(KEY_LENGTH_HEX_EXCEPTION_MESSAGE);
+ c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
+ if (state == 0)
+ c_acc = c_val * 16;
+ else
+ key[i / 2] = (byte)(c_acc | c_val);
+ state = ~state;
+ }
+ return key;
+ }
+
+ public static String keyToHex(final byte[] key) {
+ final char[] output = new char[KEY_LENGTH_HEX];
+ if (key.length != KEY_LENGTH)
+ throw new IllegalArgumentException(KEY_LENGTH_EXCEPTION_MESSAGE);
+ for (int i = 0; i < KEY_LENGTH; ++i) {
+ output[i * 2] = (char)(87 + (key[i] >> 4 & 0xf) + ((((key[i] >> 4 & 0xf) - 10) >> 8) & ~38));
+ output[i * 2 + 1] = (char)(87 + (key[i] & 0xf) + ((((key[i] & 0xf) - 10) >> 8) & ~38));
+ }
+ return new String(output);
+ }
}