java ECC 加密 解密算法

公司最近需要使用非对称加密算法进行数据加密,本来打算采用RSA的,但是CTO强制使用ECC加密算法;没办法,硬着头皮整吧!

网上的千篇一律,写法都差不多,但是有一个问题,公钥和私钥永远不会发生变法,这就比较尴尬了,而且数学学的又不是特比好,真的是很尴尬。

不过后面还是搞出来了,这里直接上代码吧!

ECC定义的常量,方便调用

package com.ktnw.utils.ecc;

public enum ECCEnum {

    ALGORITHM("EC"),
    PROVIDER("BC"),
    PUBLIC_KEY("PUBLIC_KEY"),
    PRIVATE_KEY("PRIVATE_KEY");



    private String value;

    ECCEnum(String value) {
        this.value = value;
    }

    public String value() {
        return this.value;
    }
}

ECC加密、解密封装

package com.ktnw.utils.ecc;

import com.ktnw.utils.encrypt.BASE64Decoder;

import javax.crypto.Cipher;
import javax.crypto.NullCipher;
import java.io.Serializable;
import java.security.KeyFactory;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * ecc 加密/解密
 */
public class ECCUtil implements Serializable {


    /**
     * 加密
     * @param data
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, String publicKey)
            throws Exception {
        byte[] keyBytes = BASE64Decoder.decodeBuffer(publicKey);

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ECCEnum.ALGORITHM.value());

        ECPublicKey pubKey = (ECPublicKey) keyFactory
                .generatePublic(x509KeySpec);

        Cipher cipher = new NullCipher();
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }


    /**
     * 解密
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = BASE64Decoder.decodeBuffer(privateKey);

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ECCEnum.ALGORITHM.value());

        ECPrivateKey priKey = (ECPrivateKey) keyFactory
                .generatePrivate(pkcs8KeySpec);

        Cipher cipher = new NullCipher();
        cipher.init(Cipher.DECRYPT_MODE, priKey);

        return cipher.doFinal(data);
    }
}

ECC 公钥、私钥生成器

package com.ktnw.utils.ecc;

import com.ktnw.utils.encrypt.BASE64Encoder;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;

import java.io.Serializable;
import java.security.*;
import java.util.HashMap;
import java.util.Map;

public class GenerateKey implements Serializable {

    static {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    public static Map getGenerateKey() throws NoSuchProviderException, NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ECCEnum.ALGORITHM.value(),
                ECCEnum.PROVIDER.value());
        keyPairGenerator.initialize(256, new SecureRandom());
        KeyPair kp = keyPairGenerator.generateKeyPair();
        ECPublicKey publicKey = (ECPublicKey) kp.getPublic();
        ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
        Map map = new HashMap<>();

        map.put(ECCEnum.PRIVATE_KEY.value(), BASE64Encoder.encodeBuffer(privateKey.getEncoded()));
        map.put(ECCEnum.PUBLIC_KEY.value(), BASE64Encoder.encodeBuffer(publicKey.getEncoded()));
        return map;
    }
}

到这里ECC 公钥、私钥生成、加密、解密、就写完了,下面在附带两个Base64的转码工具类

package com.ktnw.utils.encrypt;

import java.io.*;

public class BASE64Decoder extends FilterInputStream {

    private static final char[] chars = {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
            'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
            'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
            'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
            'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
            'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
            '8', '9', '+', '/'
    };

    // A mapping between char values and six-bit integers
    private static final int[] ints = new int[128];
    static {
        for (int i = 0; i < 64; i++) {
            ints[chars[i]] = i;
        }
    }

    private int charCount;
    private int carryOver;

  
    public BASE64Decoder(InputStream in) {
        super(in);
    }

    
    public int read() throws IOException {
        // Read the next non-whitespace character
        int x;
        do {
            x = in.read();
            if (x == -1) {
                return -1;
            }
        } while (Character.isWhitespace((char)x));
        charCount++;

        // The '=' sign is just padding
        if (x == '=') {
            return -1;  // effective end of stream
        }

        // Convert from raw form to 6-bit form
        x = ints[x];

        // Calculate which character we're decoding now
        int mode = (charCount - 1) % 4;

        // First char save all six bits, go for another
        if (mode == 0) {
            carryOver = x & 63;
            return read();
        }
        // Second char use previous six bits and first two new bits,
        // save last four bits
        else if (mode == 1) {
            int decoded = ((carryOver << 2) + (x >> 4)) & 255;
            carryOver = x & 15;
            return decoded;
        }
        // Third char use previous four bits and first four new bits,
        // save last two bits
        else if (mode == 2) {
            int decoded = ((carryOver << 4) + (x >> 2)) & 255;
            carryOver = x & 3;
            return decoded;
        }
        // Fourth char use previous two bits and all six new bits
        else if (mode == 3) {
            int decoded = ((carryOver << 6) + x) & 255;
            return decoded;
        }
        return -1;  // can't actually reach this line
    }

  
    public int read(byte[] buf, int off, int len) throws IOException {
        if (buf.length < (len + off - 1)) {
            throw new IOException("The input buffer is too small: " + len +
                    " bytes requested starting at offset " + off + " while the buffer " +
                    " is only " + buf.length + " bytes long.");
        }

        // This could of course be optimized
        int i;
        for (i = 0; i < len; i++) {
            int x = read();
            if (x == -1 && i == 0) {  // an immediate -1 returns -1
                return -1;
            }
            else if (x == -1) {       // a later -1 returns the chars read so far
                break;
            }
            buf[off + i] = (byte) x;
        }
        return i;
    }

   
    public static String decode(String encoded) {
        return new String(decodeToBytes(encoded));
    }

   
    public static byte[] decodeToBytes(String encoded) {
        byte[] bytes = null;
        try {
            bytes = encoded.getBytes("8859_1");
        }
        catch (UnsupportedEncodingException ignored) { }

        BASE64Decoder in = new BASE64Decoder(
                new ByteArrayInputStream(bytes));

        ByteArrayOutputStream out =
                new ByteArrayOutputStream((int) (bytes.length * 0.67));

        try {
            byte[] buf = new byte[4 * 1024];  // 4K buffer
            int bytesRead;
            while ((bytesRead = in.read(buf)) != -1) {
                out.write(buf, 0, bytesRead);
            }
            out.close();

            return out.toByteArray();
        }
        catch (IOException ignored) { return null; }
    }

    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("Usage: java Base64Decoder fileToDecode");
            return;
        }

        BASE64Decoder decoder = null;
        try {
            decoder = new BASE64Decoder(
                    new BufferedInputStream(
                            new FileInputStream(args[0])));
            byte[] buf = new byte[4 * 1024];  // 4K buffer
            int bytesRead;
            while ((bytesRead = decoder.read(buf)) != -1) {
                System.out.write(buf, 0, bytesRead);
            }
        }
        finally {
            if (decoder != null) decoder.close();
        }
    }

    public static byte[] decodeBuffer(String key) {

        return decodeToBytes(key);
    }
}

package com.ktnw.utils.encrypt;

public class BASE64Encoder {
    private static final char last2byte = (char) Integer.parseInt("00000011", 2);
    private static final char last4byte = (char) Integer.parseInt("00001111", 2);
    private static final char last6byte = (char) Integer.parseInt("00111111", 2);
    private static final char lead6byte = (char) Integer.parseInt("11111100", 2);
    private static final char lead4byte = (char) Integer.parseInt("11110000", 2);
    private static final char lead2byte = (char) Integer.parseInt("11000000", 2);
    private static final char[] encodeTable = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};

    private BASE64Encoder() {
    }

    public static String encode(byte[] from) {
        StringBuffer to = new StringBuffer((int) (from.length * 1.34) + 3);
        int num = 0;
        char currentByte = 0;
        for (int i = 0; i < from.length; i++) {
            num = num % 8;
            while (num < 8) {
                switch (num) {
                    case 0:
                        currentByte = (char) (from[i] & lead6byte);
                        currentByte = (char) (currentByte >>> 2);
                        break;
                    case 2:
                        currentByte = (char) (from[i] & last6byte);
                        break;
                    case 4:
                        currentByte = (char) (from[i] & last4byte);
                        currentByte = (char) (currentByte << 2);
                        if ((i + 1) < from.length) {
                            currentByte |= (from[i + 1] & lead2byte) >>> 6;
                        }
                        break;
                    case 6:
                        currentByte = (char) (from[i] & last2byte);
                        currentByte = (char) (currentByte << 4);
                        if ((i + 1) < from.length) {
                            currentByte |= (from[i + 1] & lead4byte) >>> 4;
                        }
                        break;
                }
                to.append(encodeTable[currentByte]);
                num += 6;
            }
        }
        if (to.length() % 4 != 0) {
            for (int i = 4 - to.length() % 4; i > 0; i--) {
                to.append("=");
            }
        }
        return to.toString();
    }

    public static String encodeBuffer(byte[] key) {

        return encode(key);
    }
}

下面是调用

package com.ktnw.utils.ecc;

import com.ktnw.utils.encrypt.BASE64Encoder;

import java.util.Map;

public class ECTest {

	public static void main(String[] argu) throws Exception {
		Map map = GenerateKey.getGenerateKey();
		String privKey = map.get(ECCEnum.PRIVATE_KEY.value());
		String pubKey = map.get(ECCEnum.PUBLIC_KEY.value());

		System.out.println("私钥:" + privKey);

		System.out.println("公钥:" + pubKey);
		String text = "java ECC 加密、解密算法,如果写的有问题,请大家踊跃评论,谢谢!";
		byte [] b = ECCUtil.encrypt(text.getBytes("UTF-8"),pubKey);
		String str = BASE64Encoder.encodeBuffer(b);
		System.out.println("密文:" + str);
		String outputStr = new String(ECCUtil.decrypt(b,privKey));
		System.out.println("原始文本:" + text);
		System.out.println("解密文本:" + outputStr);
	}
}

下面贴出我的调用结果

私钥:MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgNknUYyf2PduHcM9VVJDPS8e+GJ/2oiZR5IikDn6TKg2gCgYIKoZIzj0DAQehRANCAATGrYE98aVKYkPh/2aUsXUb39Ar/sp33kN/rnlvjP3jXnfQkJzXhkJRcZMvD3LfDVrD6F8BShPuHJA/7NWY7Xkv
公钥:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExq2BPfGlSmJD4f9mlLF1G9/QK/7Kd95Df655b4z941530JCc14ZCUXGTLw9y3w1aw+hfAUoT7hyQP+zVmO15Lw==
密文:amF2YSBFQ0Mg5Yqg5a+G44CB6Kej5a+G566X5rOV77yM5aaC5p6c5YaZ55qE5pyJ6Zeu6aKY77yM6K+35aSn5a626LiK6LeD6K+E6K6677yM6LCi6LCi77yB
原始文本:java ECC 加密、解密算法,如果写的有问题,请大家踊跃评论,谢谢!
解密文本:java ECC 加密、解密算法,如果写的有问题,请大家踊跃评论,谢谢!

 

如果大家有什么看不懂的,可以参考这篇文章

http://www.voidcn.com/article/p-xziirffi-bbr.html

你可能感兴趣的:(java,ecc,加密算法)