分别使用椭圆曲线密码术加密和解密文本消息

时间:2017-04-16 05:11:02

标签: java encryption cryptography elliptic-curve

我有这个代码,它同时使用椭圆曲线加密来加密和解密文本消息。我将代码分为两部分:加密和解密。但在解密过程中我遇到了错误。有人可以为我解决这些问题。

共享代码:

import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.Scanner;
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.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;

public class ENCRYPT {

  public static byte[] iv = new SecureRandom().generateSeed(16);

  public static void main(String[] args) {
    System.out.println("IV :" + iv);

    Scanner sc = new Scanner(System.in); // object for scanner

    System.out.println("Enter your Message:");
    String plainText = sc.nextLine();

    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);

    String encodedKeyA = Base64.getEncoder().encodeToString(secretKeyA.getEncoded());
    String encodedKeyB = Base64.getEncoder().encodeToString(secretKeyB.getEncoded());

    // Decrypt the message using 'secretKeyB'
    String decryptedPlainText = decryptString(secretKeyB, cipherText);
    System.out.println("Decrypted cipher text: " + decryptedPlainText);
    System.out.println("Secret Key A: " + encodedKeyA);
    System.out.println("Secret Key B: " + encodedKeyB);

  }

  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;
  }
}

解密代码:

//Decrypt

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.util.Base64;
import java.util.Scanner;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
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 Decrypt {

  public static byte[] iv = new SecureRandom().generateSeed(16);


  public static void main(String[] args) {

    /*  Scanner scc = new Scanner(System.in);
        System.out.println("Enter IV:");
        String ivate = scc.nextLine();
        byte[] iv = ivate.getBytes();
    */
    System.out.println("IV=" + iv);

    Scanner sc = new Scanner(System.in); // object for scanner
    System.out.println("Enter your Cipher:");
    String cipherText = sc.nextLine();

    Scanner scanner = new Scanner(System.in); // object for scanner

    System.out.println("Enter your Secret Key B:");

    String encodedKeyB = scanner.nextLine();
    byte[] decodedKeyB = Base64.getDecoder().decode(encodedKeyB);

    SecretKey secretKeyB = new SecretKeySpec(decodedKeyB, 0, decodedKeyB.length, "AES");

    // 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);
    System.out.println(" cipher text: " + cipherText);
    System.out.println("Key: " + secretKeyB);
  }

  /*  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 secretkeyB, 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 secretkeyB, String cipherText) {
    try {
      Key decryptionKey = new SecretKeySpec(secretkeyB.getEncoded(),
        secretkeyB.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;
  }
}

1 个答案:

答案 0 :(得分:3)

Artjom B完全正确地指出密钥生成需要分别为每一方进行。您需要做的是生成一个代表任何一方或仅包含共享方法的类,例如generateKeyPairderiveSecretKey,当然还有receivePublicKey。您应该能够将其用于SenderReceiver类。

只需输入密钥就完全破坏了首先执行密钥协议的想法。

但是,这不是您的代码的问题。

您在解密期间使用静态随机IV。 IV在加密期间应该是随机的,然后与解密密文的一方进行通信。这通常是通过将IV加到密文前面来实现的。

您需要在加密方法中生成IV而不是使其静态。按照您的方式重复使用IV 完全破坏了GCM模式的机密性,因为它使用下方的CTR模式。

请注意,GCM模式IV应该是12个字节,而不是16个.GCM模式IV可能只是唯一(一个nonce,number-used-once)而不是随机。