-
-
Save zcdziura/7652286 to your computer and use it in GitHub Desktop.
import java.io.UnsupportedEncodingException; | |
import java.security.InvalidAlgorithmParameterException; | |
import java.security.InvalidKeyException; | |
import java.security.Key; | |
import java.security.KeyPair; | |
import java.security.KeyPairGenerator; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.NoSuchProviderException; | |
import java.security.PrivateKey; | |
import java.security.PublicKey; | |
import java.security.SecureRandom; | |
import java.util.Enumeration; | |
import javax.crypto.BadPaddingException; | |
import javax.crypto.Cipher; | |
import javax.crypto.IllegalBlockSizeException; | |
import javax.crypto.KeyAgreement; | |
import javax.crypto.NoSuchPaddingException; | |
import javax.crypto.SecretKey; | |
import javax.crypto.ShortBufferException; | |
import javax.crypto.spec.IvParameterSpec; | |
import javax.crypto.spec.SecretKeySpec; | |
import org.bouncycastle.jce.ECNamedCurveTable; | |
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; | |
public class Test { | |
public static byte[] iv = new SecureRandom().generateSeed(16); | |
public static void main(String[] args) { | |
String plainText = "Look mah, I'm a message!"; | |
System.out.println("Original plaintext message: " + plainText); | |
// Initialize two key pairs | |
KeyPair keyPairA = generateECKeys(); | |
KeyPair keyPairB = generateECKeys(); | |
// Create two AES secret keys to encrypt/decrypt the message | |
SecretKey secretKeyA = generateSharedSecret(keyPairA.getPrivate(), | |
keyPairB.getPublic()); | |
SecretKey secretKeyB = generateSharedSecret(keyPairB.getPrivate(), | |
keyPairA.getPublic()); | |
// Encrypt the message using 'secretKeyA' | |
String cipherText = encryptString(secretKeyA, plainText); | |
System.out.println("Encrypted cipher text: " + cipherText); | |
// Decrypt the message using 'secretKeyB' | |
String decryptedPlainText = decryptString(secretKeyB, cipherText); | |
System.out.println("Decrypted cipher text: " + decryptedPlainText); | |
} | |
public static KeyPair generateECKeys() { | |
try { | |
ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec("brainpoolp256r1"); | |
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( | |
"ECDH", "BC"); | |
keyPairGenerator.initialize(parameterSpec); | |
KeyPair keyPair = keyPairGenerator.generateKeyPair(); | |
return keyPair; | |
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | |
| NoSuchProviderException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
public static SecretKey generateSharedSecret(PrivateKey privateKey, | |
PublicKey publicKey) { | |
try { | |
KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "BC"); | |
keyAgreement.init(privateKey); | |
keyAgreement.doPhase(publicKey, true); | |
SecretKey key = keyAgreement.generateSecret("AES"); | |
return key; | |
} catch (InvalidKeyException | NoSuchAlgorithmException | |
| NoSuchProviderException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
public static String encryptString(SecretKey key, String plainText) { | |
try { | |
IvParameterSpec ivSpec = new IvParameterSpec(iv); | |
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC"); | |
byte[] plainTextBytes = plainText.getBytes("UTF-8"); | |
byte[] cipherText; | |
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); | |
cipherText = new byte[cipher.getOutputSize(plainTextBytes.length)]; | |
int encryptLength = cipher.update(plainTextBytes, 0, | |
plainTextBytes.length, cipherText, 0); | |
encryptLength += cipher.doFinal(cipherText, encryptLength); | |
return bytesToHex(cipherText); | |
} catch (NoSuchAlgorithmException | NoSuchProviderException | |
| NoSuchPaddingException | InvalidKeyException | |
| InvalidAlgorithmParameterException | |
| UnsupportedEncodingException | ShortBufferException | |
| IllegalBlockSizeException | BadPaddingException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
public static String decryptString(SecretKey key, String cipherText) { | |
try { | |
Key decryptionKey = new SecretKeySpec(key.getEncoded(), | |
key.getAlgorithm()); | |
IvParameterSpec ivSpec = new IvParameterSpec(iv); | |
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC"); | |
byte[] cipherTextBytes = hexToBytes(cipherText); | |
byte[] plainText; | |
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, ivSpec); | |
plainText = new byte[cipher.getOutputSize(cipherTextBytes.length)]; | |
int decryptLength = cipher.update(cipherTextBytes, 0, | |
cipherTextBytes.length, plainText, 0); | |
decryptLength += cipher.doFinal(plainText, decryptLength); | |
return new String(plainText, "UTF-8"); | |
} catch (NoSuchAlgorithmException | NoSuchProviderException | |
| NoSuchPaddingException | InvalidKeyException | |
| InvalidAlgorithmParameterException | |
| IllegalBlockSizeException | BadPaddingException | |
| ShortBufferException | UnsupportedEncodingException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
public static String bytesToHex(byte[] data, int length) { | |
String digits = "0123456789ABCDEF"; | |
StringBuffer buffer = new StringBuffer(); | |
for (int i = 0; i != length; i++) { | |
int v = data[i] & 0xff; | |
buffer.append(digits.charAt(v >> 4)); | |
buffer.append(digits.charAt(v & 0xf)); | |
} | |
return buffer.toString(); | |
} | |
public static String bytesToHex(byte[] data) { | |
return bytesToHex(data, data.length); | |
} | |
public static byte[] hexToBytes(String string) { | |
int length = string.length(); | |
byte[] data = new byte[length / 2]; | |
for (int i = 0; i < length; i += 2) { | |
data[i / 2] = (byte) ((Character.digit(string.charAt(i), 16) << 4) + Character | |
.digit(string.charAt(i + 1), 16)); | |
} | |
return data; | |
} | |
} |
Original plaintext message: Look mah, I'm a message! | |
Encrypted cipher text: 7AFCF3F9A6213FA6900D3DFC12553379580FC7AD362E2C2E28F548FC2AF42F07CF2B057537376F36 | |
Decrypted cipher text: Look mah, I'm a message! |
Excuse me, I have occurred an error NoSuchAlgorithmException
:
java.lang.RuntimeException: Unable to start service com.example.helloworld.crypto.ecc.ECCService@1732d6 with Intent { cmp=com.example.helloworld/.crypto.ecc.ECCService (has extras) }: java.security.NoSuchAlgorithmException: no such algorithm: ECDH for provider BC
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3346)
at android.app.ActivityThread.-wrap21(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1585)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6169)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:891)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781)
Caused by: java.security.NoSuchAlgorithmException: no such algorithm: ECDH for provider BC
at sun.security.jca.GetInstance.getService(GetInstance.java:87)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
at java.security.KeyPairGenerator.getInstance(KeyPairGenerator.java:286)
at com.example.helloworld.crypto.ecc.ECDH.generateKeyPair(ECDH.kt:11)
at com.example.helloworld.crypto.ecc.ECCService.testECDH(ECCService.kt:57)
at com.example.helloworld.crypto.ecc.ECCService.onStartCommand(ECCService.kt:16)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3329)
at android.app.ActivityThread.-wrap21(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1585)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6169)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:891)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781)
It's my code:
class ECDH {
fun generateKeyPair(): KeyPair {
val parameterSpec = ECNamedCurveTable.getParameterSpec("brainpoolp256r1")
val keyPairGenerator = KeyPairGenerator.getInstance("ECDH", "BC")
keyPairGenerator.initialize(parameterSpec)
return keyPairGenerator.generateKeyPair()
}
fun generateSharedSecret(privateKey: PrivateKey, publicKey: PublicKey): SecretKey? {
val keyAgreement = KeyAgreement.getInstance("ECDH", "BC")
keyAgreement.init(privateKey)
keyAgreement.doPhase(publicKey, true)
return keyAgreement.generateSecret("AES")
}
}
private fun testECDH() {
Security.addProvider(org.bouncycastle.jce.provider.BouncyCastleProvider())
var providers = Security.getProviders()
for (providers in providers) {
println("providers: $providers")
}
val ecdh = ECDH()
val keyPair = ecdh.generateKeyPair()
val keyPair1 = ecdh.generateKeyPair()
var secretKey = ecdh.generateSharedSecret(keyPair.private, keyPair1.public)
var secretKey1 = ecdh.generateSharedSecret(keyPair1.private, keyPair.public)
println("secretKey:$secretKey")
println("secretKey1:$secretKey1")
}
\Jarfiles>javac Test.java
Test.java:23: error: package org.bouncycastle does not exist
import org.bouncycastle.*;
^
Test.java:24: error: package org.bouncycastle.jce.spec does not exist
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
^
Test.java:54: error: cannot find symbol
ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec("brainpoolp256r1");
^
symbol: class ECNamedCurveParameterSpec
location: class Test
Test.java:54: error: cannot find symbol
ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec("brainpoolp256r1");
^
symbol: variable ECNamedCurveTable
location: class Test
4 errors
Iam getting these errors please help me out
You can download it at https://www.bouncycastle.org/latest_releases.html, and then put it in you project libs.
Excuse me, I have occurred an error
NoSuchAlgorithmException
:java.lang.RuntimeException: Unable to start service com.example.helloworld.crypto.ecc.ECCService@1732d6 with Intent { cmp=com.example.helloworld/.crypto.ecc.ECCService (has extras) }: java.security.NoSuchAlgorithmException: no such algorithm: ECDH for provider BC at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3346) at android.app.ActivityThread.-wrap21(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1585) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6169) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:891) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781) Caused by: java.security.NoSuchAlgorithmException: no such algorithm: ECDH for provider BC at sun.security.jca.GetInstance.getService(GetInstance.java:87) at sun.security.jca.GetInstance.getInstance(GetInstance.java:206) at java.security.KeyPairGenerator.getInstance(KeyPairGenerator.java:286) at com.example.helloworld.crypto.ecc.ECDH.generateKeyPair(ECDH.kt:11) at com.example.helloworld.crypto.ecc.ECCService.testECDH(ECCService.kt:57) at com.example.helloworld.crypto.ecc.ECCService.onStartCommand(ECCService.kt:16) at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3329) at android.app.ActivityThread.-wrap21(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1585) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6169) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:891) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781)It's my code:
class ECDH { fun generateKeyPair(): KeyPair { val parameterSpec = ECNamedCurveTable.getParameterSpec("brainpoolp256r1") val keyPairGenerator = KeyPairGenerator.getInstance("ECDH", "BC") keyPairGenerator.initialize(parameterSpec) return keyPairGenerator.generateKeyPair() } fun generateSharedSecret(privateKey: PrivateKey, publicKey: PublicKey): SecretKey? { val keyAgreement = KeyAgreement.getInstance("ECDH", "BC") keyAgreement.init(privateKey) keyAgreement.doPhase(publicKey, true) return keyAgreement.generateSecret("AES") } } private fun testECDH() { Security.addProvider(org.bouncycastle.jce.provider.BouncyCastleProvider()) var providers = Security.getProviders() for (providers in providers) { println("providers: $providers") } val ecdh = ECDH() val keyPair = ecdh.generateKeyPair() val keyPair1 = ecdh.generateKeyPair() var secretKey = ecdh.generateSharedSecret(keyPair.private, keyPair1.public) var secretKey1 = ecdh.generateSharedSecret(keyPair1.private, keyPair.public) println("secretKey:$secretKey") println("secretKey1:$secretKey1") }
I solved the problem,
change KeyPairGenerator.getInstance("ECDH", "BC")
to KeyPairGenerator.getInstance("ECDH", org.bouncycastle.jce.provider.BouncyCastleProvider())
@ zcdziura Hi, I just wanted to understand the example which you have shared uses an asymmetric form of encryption or symmetric. I am asking this question as to when I implemented this solution and after generating a shared secret I am getting both the key as same. So I am a bit doubtful about this. It will be great if you can help me to understand this.
The private and public keys are the same in the keypair.
Security Provider "BC" will not work from API level 28.
Try to add SpongyCastle manually:
Security.insertProviderAt(new BouncyCastleProvider(), 1);
add this to your build.gradle dependencies:
Make sure the BouncyCastleProvider() was coming from spongycastle:
import org.spongycastle.jce.provider.BouncyCastleProvider