This is an automated email from the ASF dual-hosted git repository.

toulmean pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git


The following commit(s) were added to refs/heads/main by this push:
     new 3257e45  Add methods to encrypt and decrypt with secp256k1
     new 2a30e2a  Merge pull request #387 from atoulme/encrypt_decrypt
3257e45 is described below

commit 3257e45cfa9d5daad2dd9e05308c7cebacdec6c5
Author: Antoine Toulme <anto...@lunar-ocean.com>
AuthorDate: Mon Mar 21 22:35:40 2022 -0700

    Add methods to encrypt and decrypt with secp256k1
---
 .../apache/tuweni/crypto/DecryptionException.java  | 23 ++++++++++
 .../apache/tuweni/crypto/EncryptionException.java  | 23 ++++++++++
 .../java/org/apache/tuweni/crypto/SECP256K1.java   | 51 ++++++++++++++++++++++
 .../org/apache/tuweni/crypto/SECP256K1Test.java    |  8 ++++
 4 files changed, 105 insertions(+)

diff --git 
a/crypto/src/main/java/org/apache/tuweni/crypto/DecryptionException.java 
b/crypto/src/main/java/org/apache/tuweni/crypto/DecryptionException.java
new file mode 100644
index 0000000..2c3a685
--- /dev/null
+++ b/crypto/src/main/java/org/apache/tuweni/crypto/DecryptionException.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding 
copyright ownership. The ASF licenses this file
+ * to You under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.tuweni.crypto;
+
+/**
+ * Exception thrown when decryption fails.
+ */
+public class DecryptionException extends RuntimeException {
+
+  public DecryptionException(Throwable t) {
+    super(t);
+  }
+}
diff --git 
a/crypto/src/main/java/org/apache/tuweni/crypto/EncryptionException.java 
b/crypto/src/main/java/org/apache/tuweni/crypto/EncryptionException.java
new file mode 100644
index 0000000..4f0d398
--- /dev/null
+++ b/crypto/src/main/java/org/apache/tuweni/crypto/EncryptionException.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding 
copyright ownership. The ASF licenses this file
+ * to You under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.tuweni.crypto;
+
+/**
+ * Exception thrown when encryption fails.
+ */
+public class EncryptionException extends RuntimeException {
+
+  public EncryptionException(Throwable t) {
+    super(t);
+  }
+}
diff --git a/crypto/src/main/java/org/apache/tuweni/crypto/SECP256K1.java 
b/crypto/src/main/java/org/apache/tuweni/crypto/SECP256K1.java
index 7e323cc..167bfb9 100644
--- a/crypto/src/main/java/org/apache/tuweni/crypto/SECP256K1.java
+++ b/crypto/src/main/java/org/apache/tuweni/crypto/SECP256K1.java
@@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkState;
 import static java.nio.file.StandardOpenOption.READ;
 import static org.apache.tuweni.crypto.Hash.keccak256;
 import static org.apache.tuweni.crypto.SECP256K1.Parameters.CURVE;
+import static org.apache.tuweni.crypto.SECP256K1.Parameters.PARAMETER_SPEC;
 import static org.apache.tuweni.io.file.Files.atomicReplace;
 
 import org.apache.tuweni.bytes.Bytes;
@@ -37,6 +38,7 @@ import java.nio.CharBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.file.Path;
 import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
@@ -44,6 +46,7 @@ import java.security.SecureRandom;
 import java.security.spec.ECGenParameterSpec;
 import java.util.Arrays;
 import javax.annotation.Nullable;
+import javax.crypto.Cipher;
 import javax.security.auth.Destroyable;
 
 import com.google.common.base.Objects;
@@ -59,6 +62,12 @@ import org.bouncycastle.crypto.signers.ECDSASigner;
 import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
 import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
 import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
+import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.jce.spec.ECPrivateKeySpec;
+import org.bouncycastle.jce.spec.ECPublicKeySpec;
 import org.bouncycastle.math.ec.ECAlgorithms;
 import org.bouncycastle.math.ec.ECPoint;
 import org.bouncycastle.math.ec.FixedPointCombMultiplier;
@@ -91,6 +100,7 @@ public final class SECP256K1 {
   // Lazily initialize parameters by using java initialization on demand
   public static final class Parameters {
     public static final ECDomainParameters CURVE;
+    static final ECParameterSpec PARAMETER_SPEC;
     static final BigInteger CURVE_ORDER;
     static final BigInteger HALF_CURVE_ORDER;
     static final KeyPairGenerator KEY_PAIR_GENERATOR;
@@ -105,6 +115,11 @@ public final class SECP256K1 {
       }
       X9ECParameters params = SECNamedCurves.getByName(CURVE_NAME);
       CURVE = new ECDomainParameters(params.getCurve(), params.getG(), 
params.getN(), params.getH());
+      PARAMETER_SPEC = new ECParameterSpec(
+              params.getCurve(),
+              CURVE.getG(),
+              CURVE.getN(),
+              CURVE.getH());
       CURVE_ORDER = CURVE.getN();
       HALF_CURVE_ORDER = CURVE_ORDER.shiftRight(1);
       if (CURVE_ORDER.compareTo(SecP256K1Curve.q) >= 0) {
@@ -212,6 +227,42 @@ public final class SECP256K1 {
   }
 
   /**
+   * Encrypts bytes using a public key.
+   * @param publicKey the public key for encryption
+   * @param payload the payload to encrypt
+   * @return the encrypted data
+   */
+  public static Bytes encrypt(SECP256K1.PublicKey publicKey, Bytes payload) {
+    try {
+      ECPoint ecPoint = publicKey.asEcPoint();
+      ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, PARAMETER_SPEC);
+      KeyFactory keyFactory = KeyFactory.getInstance("EC");
+      java.security.PublicKey bcKey = keyFactory.generatePublic(keySpec);
+
+      Cipher iesCipher = Cipher.getInstance("ECIES", "BC");
+      iesCipher.init(Cipher.ENCRYPT_MODE, bcKey);
+      byte[] output = iesCipher.doFinal(payload.toArrayUnsafe());
+      return Bytes.wrap(output);
+    } catch(Exception e) {
+      throw new EncryptionException(e);
+    }
+  }
+
+  public static Bytes decrypt(SECP256K1.SecretKey secretKey, Bytes encrypted) {
+    try {
+      ECPrivateKeySpec keySpec = new 
ECPrivateKeySpec(secretKey.bytes().toBigInteger(), PARAMETER_SPEC);
+      KeyFactory keyFactory = KeyFactory.getInstance("EC");
+      java.security.PrivateKey bcKey = keyFactory.generatePrivate(keySpec);
+      Cipher iesCipher = Cipher.getInstance("ECIES", "BC");
+      iesCipher.init(Cipher.DECRYPT_MODE, bcKey);
+      byte[] output = iesCipher.doFinal(encrypted.toArrayUnsafe());
+      return Bytes.wrap(output);
+    } catch (Exception e) {
+      throw new DecryptionException(e);
+    }
+  }
+
+  /**
    * Generates an ECDSA signature.
    *
    * @param data The data to sign.
diff --git a/crypto/src/test/java/org/apache/tuweni/crypto/SECP256K1Test.java 
b/crypto/src/test/java/org/apache/tuweni/crypto/SECP256K1Test.java
index 75f7352..9223910 100644
--- a/crypto/src/test/java/org/apache/tuweni/crypto/SECP256K1Test.java
+++ b/crypto/src/test/java/org/apache/tuweni/crypto/SECP256K1Test.java
@@ -354,4 +354,12 @@ class SECP256K1Test {
     Bytes32 otherSharedSecret = 
SECP256K1.calculateKeyAgreement(otherKP.secretKey(), kp.publicKey());
     assertEquals(sharedSecret, otherSharedSecret);
   }
+
+  @Test
+  void encryptDecrypt() {
+    KeyPair kp = SECP256K1.KeyPair.random();
+    Bytes encrypted = SECP256K1.encrypt(kp.publicKey(), 
Bytes.fromHexString("0xdeadbeef"));
+    Bytes decrypted = SECP256K1.decrypt(kp.secretKey(), encrypted);
+    assertEquals(Bytes.fromHexString("0xdeadbeef"), decrypted);
+  }
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@tuweni.apache.org
For additional commands, e-mail: commits-h...@tuweni.apache.org

Reply via email to