有爱丽丝和鲍勃。我想实现以下过程:
我正在使用bouncycastle的ECElGamalEncryptor类。我的问题是,据我所知,此类使用公共密钥对椭圆曲线上的点进行加密,但是我的AES密钥不是ECPoint,而是十六进制。
假装我拥有用于AES加密的128位密钥:
6D5A7134743777397A24432646294A40
这就是我到目前为止所拥有的:
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.ec.ECElGamalDecryptor;
import org.bouncycastle.crypto.ec.ECElGamalEncryptor;
import org.bouncycastle.crypto.ec.ECPair;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.math.ec.ECPoint;
class TestClass {
public static void main(String[] argv) {
// Get domain parameters for example curve secp256r1
X9ECParameters ecp = SECNamedCurves.getByName("secp256r1");
ECDomainParameters domainParams = new ECDomainParameters(ecp.getCurve(),
ecp.getG(), ecp.getN(), ecp.getH(),
ecp.getSeed());
// Generate a private key and a public key
AsymmetricCipherKeyPair keyPair;
ECKeyGenerationParameters keyGenParams = new ECKeyGenerationParameters(domainParams, new SecureRandom());
ECKeyPairGenerator generator = new ECKeyPairGenerator();
generator.init(keyGenParams);
keyPair = generator.generateKeyPair();
ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getD().toByteArray();
// Get ECPoint Q from privateKey
ECPoint Q = domainParams.getG().multiply(new BigInteger(privateKeyBytes));
//Initialize ECElGamalEncryptor
ECElGamalEncryptor elgamalEn = new ECElGamalEncryptor();
elgamalEn.init(publicKey);
ECPair encrypted = elgamalEn.encrypt(Q);
//Encryption
ECElGamalDecryptor elgamalDe = new ECElGamalDecryptor();
elgamalDe.init(privateKey);
ECPoint original = elgamalDe.decrypt(encrypted);
}
}
因此,我能够初始化ECElGamalEncryptor并使用公共密钥加密ECPointQ。但是实际上,我想加密AES密钥,不知道现在该怎么做。
答案 0 :(得分:4)
让我尝试改写您的问题的一部分,以使它变得更加清晰,并带有一些必要的符号。您对计划的措辞理解起来有些繁琐。但是,正如@JamesKPolk和@MaartenBodewes指出的那样,支持加密的椭圆曲线密码学需要一个称为ECIES的IES方案,可以将ECDH和对称加密方案(例如AES)结合使用。因此,让我们重新审视您试图与Alice和Bob一起实施的方案。
引导程序
SecretKey
和IV
组成。在此示例中,我们将使用AES256
所需方案
m
,以生成加密消息 e m 。
SecretKey
和一个IV
向量。在下面的代码示例中,我们将此元组称为AESPair
。SecretKey (SK) || IV
消息,以获得 e sk || iv 。
SharedSecret
。我们称之为SSK 1 SharedSecet
。我们称其为SSK 2 代码
助手功能
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String convertBytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars).toLowerCase();
}
public static byte[] hexStringToByteArray(String hexString){
byte[] bytes = new byte[hexString.length() / 2];
for(int i = 0; i < hexString.length(); i += 2){
String sub = hexString.substring(i, i + 2);
Integer intVal = Integer.parseInt(sub, 16);
bytes[i / 2] = intVal.byteValue();
String hex = "".format("0x%x", bytes[i / 2]);
}
return bytes;
}
ECC.java
public class ECC {
// Both Alice and Bob agree upon this value in some manner before starting this protocol.
public static byte[] iv = new SecureRandom().generateSeed(16);
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
public static KeyPair generateKeyPair() throws InvalidAlgorithmParameterException, NoSuchProviderException, NoSuchAlgorithmException {
ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDH", "BC");
keyPairGenerator.initialize(parameterSpec);
return keyPairGenerator.generateKeyPair();
}
public static SecretKey generateSharedSecret(PrivateKey privateKey, PublicKey publicKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException {
KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "BC");
keyAgreement.init(privateKey);
keyAgreement.doPhase(publicKey, true);
return keyAgreement.generateSecret("AES");
}
public static byte[] encrypt(SecretKey key, byte[] plainTextBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException, ShortBufferException, BadPaddingException, IllegalBlockSizeException {
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
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 cipherText;
}
public static byte[] decrypt(SecretKey key, byte[] cipherTextBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException, ShortBufferException, BadPaddingException, IllegalBlockSizeException {
Key decryptionKey = new SecretKeySpec(key.getEncoded(),
key.getAlgorithm());
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
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 plainText;
}
}
AES256.java
public class AES256 {
public static AESPair generateKeyPair() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
SecretKey key = keyGenerator.generateKey();
byte[] IV = new byte[16];
SecureRandom random = new SecureRandom();
random.nextBytes(IV);
AESPair response = new AESPair(key, IV);
return response;
}
public static byte[] encrypt(byte[] plainText, SecretKey key, byte[] IV) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
byte[] cipherText = cipher.doFinal(plainText);
return cipherText;
}
public static byte[] decrypt(byte[] cipherText, SecretKey key, byte[] IV) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decryptedText = cipher.doFinal(cipherText);
return decryptedText;
}
public static byte[] serializeSecretKey (SecretKey key) {
return key.getEncoded();
}
public static SecretKey deserializeSecretKey (byte[] sk) {
return new SecretKeySpec(sk, 0, sk.length, "AES");
}
}
AESPair.java ,它是AES的相应帮助程序。
public class AESPair {
private SecretKey key;
private byte[] IV;
public void setIV(byte[] IV) {
this.IV = IV;
}
public void setKey(SecretKey key) {
this.key = key;
}
public byte[] getIV() {
return IV;
}
public SecretKey getKey() {
return key;
}
public AESPair(SecretKey sk, byte[] ivBytes) {
key = sk;
IV = ivBytes;
}
// This takes in SK || IV for AES256 and creates the SecretKey object and corresponding IV byte array.
public AESPair(byte[] skConcatIVBytes) {
int total_bytes = skConcatIVBytes.length;
// FOR AES256 the key is 32 bytes and the IV is 16 bytes
byte[] sk = Arrays.copyOfRange(skConcatIVBytes, 0, 32);
byte[] iv = Arrays.copyOfRange(skConcatIVBytes, 32, total_bytes);
key = new SecretKeySpec(sk, 0, sk.length, Constant.AES);
IV = iv;
}
}
现在我们有了所需的零件,让我们将所需的方案组合在一起作为测试。
@Test
public void test_scheme_ecc() throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, ShortBufferException {
String plainText = "plaintext message from alice to bob";
System.out.println("Original plaintext message: " + plainText);
AESPair aliceAESPair = AES256.generateKeyPair();
AESPair bobAESPair = AES256.generateKeyPair();
byte[] encryptedPlainTextMessageFromAlice = AES256.encrypt(plainText.getBytes(StandardCharsets.UTF_8), aliceAESPair.getKey(), aliceAESPair.getIV());
System.out.println("Alice encrypted message : " + convertBytesToHex(encryptedPlainTextMessageFromAlice));
// Necessary Key + IV information to reconstruct the key
byte[] keyInformation = ByteBuffer.allocate(aliceAESPair.getKey().getEncoded().length + aliceAESPair.getIV().length)
.put(aliceAESPair.getKey().getEncoded())
.put(aliceAESPair.getIV())
.array();
System.out.println("Alice's SK || IV : " + convertBytesToHex(keyInformation));
// Initialize two key pairs
KeyPair aliceECKeyPair = ECC.generateKeyPair();
KeyPair bobECKeyPair = ECC.generateKeyPair();
System.out.println("Alice EC PK : " + convertBytesToHex(aliceECKeyPair.getPublic().getEncoded()));
System.out.println("Bob EC PK : " + convertBytesToHex(bobECKeyPair.getPublic().getEncoded()));
// Create two AES secret keys to encrypt/decrypt the message
SecretKey aliceSharedSecret = ECC.generateSharedSecret(aliceECKeyPair.getPrivate(), bobECKeyPair.getPublic());
System.out.println("Alice Shared Secret Key : " + convertBytesToHex(aliceSharedSecret.getEncoded()));
// Encrypt the message using 'aliceSharedSecret'
byte[] cipherText = ECC.encrypt(aliceSharedSecret, keyInformation);
System.out.println("Encrypted cipher text: " + convertBytesToHex(cipherText));
// Decrypt the message using 'bobSharedSecret'
SecretKey bobSharedSecret = ECC.generateSharedSecret(bobECKeyPair.getPrivate(), aliceECKeyPair.getPublic());
System.out.println("Bob Shared Secret Key : " + convertBytesToHex(bobSharedSecret.getEncoded()));
byte[] decrypted_EncryptedTextFromAlice = ECC.decrypt(bobSharedSecret, cipherText);
System.out.println("Decrypted cipher text to obtain Alice generated secret key: " + convertBytesToHex(decrypted_EncryptedTextFromAlice));
AESPair reconstructedKey = new AESPair(decrypted_EncryptedTextFromAlice);
byte[] decryptedText = AES256.decrypt(encryptedPlainTextMessageFromAlice, reconstructedKey.getKey(), reconstructedKey.getIV());
System.out.println("Decrypted plain text message : " + new String(decryptedText));
}
这是测试的结果:
Original plaintext message: plaintext message from alice to bob
Alice encrypted message : 9d273ea89ab6b8d170941d2578f0d4e11b1d6a3be199189dbbf4a5ff64fbf1348edbb459e38dac17aad6a68b1a95300f
Alice's SK || IV : 857248ab0171a652926fcc46353831965dd2d98cb4920de7d629c07250bc60fb60306f67d2c44e725b2e8344d970b34b
Alice EC PK : 3059301306072a8648ce3d020106082a8648ce3d030107034200042499c59fea8ab010782444825c7872c04407a4f034d907ca9014b9f8d4be1226cb9fc9eff57f8e0e7b8e1aa83290c6d6c3a56aeeef3490e1e55476e94abb4128
Bob EC PK : 3059301306072a8648ce3d020106082a8648ce3d03010703420004d91562882f30b54177449941b9812b17ac5a59d2b80cc5fbaef833426152623dfb17965ba9897edd5da26b4044071882f8ae53ce37c24f0ea5b55b7e42b689ac
Alice Shared Secret Key : 3fa7b4ae68ff51296293b69ac1b0d8d139bf3f6a60732a124734a19f2987b772
Encrypted cipher text: 758506913bee96816f7a3190720ce7f01ddb8acbeaef1e669af420c04036a4b2ab446ce2a2bee62f603a0400b9076c927f2eeffc2a4cec0ffad756fed19dc6d9
Bob Shared Secret Key : 3fa7b4ae68ff51296293b69ac1b0d8d139bf3f6a60732a124734a19f2987b772
Decrypted cipher text to obtain Alice generated secret key: 857248ab0171a652926fcc46353831965dd2d98cb4920de7d629c07250bc60fb60306f67d2c44e725b2e8344d970b34b
Decrypted plain text message : plaintext message from alice to bob
BUILD SUCCESSFUL in 1s
测试用例代码的说明
Alice
生成了AES256密钥和IV "plain text from alice to bob"
进行加密。key || IV
的串联创建一个新的字节数组。这是应该加密的消息,并通过ECIES发送给Bob。ECC.generateKeyPair()
方法进行。Shared Secret
,它是对称的SecretKey
byte[]
,该消息将转换为AESPair
对象,从而创建必要的SecretKey
和IV
。"plain text from alice to bob"
希望这会有所帮助。如果您需要澄清,请告诉我。