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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]