From ee57bd7363460b1ad3d2fee51159e68a6a45ad14 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sat, 13 Oct 2018 10:39:20 +0000
Subject: [PATCH] Data: Add encryption types for PublicKey, PrivateKey

---
 core/java/src/net/i2p/data/PrivateKey.java | 63 +++++++++++++++++++---
 core/java/src/net/i2p/data/PublicKey.java  | 59 +++++++++++++++++++-
 2 files changed, 114 insertions(+), 8 deletions(-)

diff --git a/core/java/src/net/i2p/data/PrivateKey.java b/core/java/src/net/i2p/data/PrivateKey.java
index 163edcc3f5..5eafbbd8ae 100644
--- a/core/java/src/net/i2p/data/PrivateKey.java
+++ b/core/java/src/net/i2p/data/PrivateKey.java
@@ -11,6 +11,7 @@ package net.i2p.data;
 
 import java.util.Arrays;
 
+import net.i2p.crypto.EncType;
 import net.i2p.crypto.KeyGenerator;
 
 /**
@@ -18,20 +19,42 @@ import net.i2p.crypto.KeyGenerator;
  * A private key is 256byte Integer. The private key represents only the 
  * exponent, not the primes, which are constant and defined in the crypto spec.
  *
- * Note that we use short exponents, so all but the last 28.25 bytes are zero.
- * See http://www.i2p2.i2p/how_cryptography for details.
+ * As of release 0.9.38, keys of arbitrary length and type are supported.
+ * See EncType.
  *
  * @author jrandom
  */
 public class PrivateKey extends SimpleDataStructure {
-    public final static int KEYSIZE_BYTES = 256;
+    private static final EncType DEF_TYPE = EncType.ELGAMAL_2048;
+    public final static int KEYSIZE_BYTES = DEF_TYPE.getPrivkeyLen();
+
+    private final EncType _type;
 
     public PrivateKey() {
+        this(DEF_TYPE);
+    }
+
+    /**
+     *  @param type non-null
+     *  @since 0.9.38
+     */
+    public PrivateKey(EncType type) {
         super();
+        _type = type;
     }
 
     public PrivateKey(byte data[]) {
+        this(DEF_TYPE, data);
+    }
+
+    /**
+     *  @param type non-null
+     *  @param data must be non-null
+     *  @since 0.9.38
+     */
+    public PrivateKey(EncType type, byte data[]) {
         super(data);
+        _type = type;
     }
 
     /** constructs from base64
@@ -39,12 +62,20 @@ public class PrivateKey extends SimpleDataStructure {
      * on a prior instance of PrivateKey
      */
     public PrivateKey(String base64Data) throws DataFormatException {
-        super();
+        this(DEF_TYPE);
         fromBase64(base64Data);
     }
 
     public int length() {
-        return KEYSIZE_BYTES;
+        return _type.getPrivkeyLen();
+    }
+
+    /**
+     *  @return non-null
+     *  @since 0.9.38
+     */
+    public EncType getType() {
+        return _type;
     }
 
     /** derives a new PublicKey object derived from the secret contents
@@ -56,6 +87,23 @@ public class PrivateKey extends SimpleDataStructure {
         return KeyGenerator.getPublicKey(this);
     }
 
+    /**
+     *  @since 0.9.38
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(64);
+        buf.append("[PrivateKey ").append(_type).append(": ");
+        int length = length();
+        if (_data == null) {
+            buf.append("null");
+        } else {
+            buf.append("size: ").append(length);
+        }
+        buf.append(']');
+        return buf.toString();
+    }
+
     /**
      * We assume the data has enough randomness in it, so use the last 4 bytes for speed.
      * Overridden since we use short exponents, so the first 227 bytes are all zero.
@@ -64,6 +112,8 @@ public class PrivateKey extends SimpleDataStructure {
     public int hashCode() {
         if (_data == null)
             return 0;
+        if (_type != DEF_TYPE)
+            return DataHelper.hashCode(_data);
         int rv = _data[KEYSIZE_BYTES - 4];
         for (int i = 1; i < 4; i++)
             rv ^= (_data[i + (KEYSIZE_BYTES - 4)] << (i*8));
@@ -74,6 +124,7 @@ public class PrivateKey extends SimpleDataStructure {
     public boolean equals(Object obj) {
         if (obj == this) return true;
         if ((obj == null) || !(obj instanceof PrivateKey)) return false;
-        return Arrays.equals(_data, ((PrivateKey) obj)._data);
+        PrivateKey p = (PrivateKey) obj;
+        return _type == p._type && Arrays.equals(_data, p._data);
     }
 }
diff --git a/core/java/src/net/i2p/data/PublicKey.java b/core/java/src/net/i2p/data/PublicKey.java
index 874e65e353..cf2bae7692 100644
--- a/core/java/src/net/i2p/data/PublicKey.java
+++ b/core/java/src/net/i2p/data/PublicKey.java
@@ -12,19 +12,27 @@ package net.i2p.data;
 import java.io.InputStream;
 import java.io.IOException;
 
+import net.i2p.crypto.EncType;
+
 /**
  * Defines the PublicKey as defined by the I2P data structure spec.
  * A public key is 256byte Integer. The public key represents only the 
  * exponent, not the primes, which are constant and defined in the crypto spec.
  *
+ * As of release 0.9.38, keys of arbitrary length and type are supported.
+ * See EncType.
+ *
  * @author jrandom
  */
 public class PublicKey extends SimpleDataStructure {
-    public final static int KEYSIZE_BYTES = 256;
+    private static final EncType DEF_TYPE = EncType.ELGAMAL_2048;
+    public final static int KEYSIZE_BYTES = DEF_TYPE.getPubkeyLen();
     private static final int CACHE_SIZE = 1024;
 
     private static final SDSCache<PublicKey> _cache = new SDSCache<PublicKey>(PublicKey.class, KEYSIZE_BYTES, CACHE_SIZE);
 
+    private final EncType _type;
+
     /**
      * Pull from cache or return new.
      * Deprecated - used only by deprecated Destination.readBytes(data, off)
@@ -45,12 +53,31 @@ public class PublicKey extends SimpleDataStructure {
     }
 
     public PublicKey() {
+        this(DEF_TYPE);
+    }
+
+    /**
+     *  @param type if null, type is unknown
+     *  @since 0.9.38
+     */
+    public PublicKey(EncType type) {
         super();
+        _type = type;
     }
 
     /** @param data must be non-null */
     public PublicKey(byte data[]) {
+        this(DEF_TYPE, data);
+    }
+
+    /**
+     *  @param type if null, type is unknown
+     *  @param data must be non-null
+     *  @since 0.9.38
+     */
+    public PublicKey(EncType type, byte data[]) {
         super();
+        _type = type;
         if (data == null)
             throw new IllegalArgumentException("Data must be specified");
         _data = data;
@@ -61,18 +88,46 @@ public class PublicKey extends SimpleDataStructure {
      * on a prior instance of PublicKey
      */
     public PublicKey(String base64Data)  throws DataFormatException {
-        super();
+        this(DEF_TYPE);
         fromBase64(base64Data);
     }
     
     public int length() {
+        if (_type != null)
+            return _type.getPubkeyLen();
+        if (_data != null)
+            return _data.length;
         return KEYSIZE_BYTES;
     }
 
+    /**
+     *  @return null if unknown
+     *  @since 0.9.38
+     */
+    public EncType getType() {
+        return _type;
+    }
+
     /**
      *  @since 0.9.17
      */
     public static void clearCache() {
         _cache.clear();
     }
+
+    /**
+     *  @since 0.9.38
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(64);
+        buf.append("[PublicKey ").append((_type != null) ? _type.toString() : "unknown type").append(' ');
+        if (_data == null) {
+            buf.append("null");
+        } else {
+            buf.append("size: ").append(length());
+        }
+        buf.append(']');
+        return buf.toString();
+    }
 }
-- 
GitLab