从jPBC保存和加载非对称密钥 [英] Save and load asymmetric keys from jPBC

查看:206
本文介绍了从jPBC保存和加载非对称密钥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要与存储/还原用于解密Java中字符串的加密密钥的简便方法

但是我的情况不同.在上面的链接中,他们使用的是javax.crypto.*,但在我的情况下,我使用的是org.bouncycastle.crypto.*it.unisa.dia.gas.crypto.jpbc.fe.abe.gghsw13.generators.*

But my case is different. In the above link they are using javax.crypto.* but in my case I am using org.bouncycastle.crypto.* and it.unisa.dia.gas.crypto.jpbc.fe.abe.gghsw13.generators.*

我想将主密钥,公钥和私钥存储在不同的文件中,并且还从文件中检索那些密钥.怎么做?

I want to store master-secret-key, public-key and private-key in different files and also retrieve those keys from files. How to do it ?

下面是我留下 TODO 的代码.可以在 github 上找到工作代码.

Below is the code where I left TODOs. Working code can be found on github.

import it.unisa.dia.gas.crypto.circuit.BooleanCircuit;
import it.unisa.dia.gas.crypto.circuit.BooleanCircuit.BooleanCircuitGate;
import it.unisa.dia.gas.crypto.jpbc.fe.abe.gghsw13.engines.GGHSW13KEMEngine;
import it.unisa.dia.gas.crypto.jpbc.fe.abe.gghsw13.generators.GGHSW13KeyPairGenerator;
import it.unisa.dia.gas.crypto.jpbc.fe.abe.gghsw13.generators.GGHSW13ParametersGenerator;
import it.unisa.dia.gas.crypto.jpbc.fe.abe.gghsw13.generators.GGHSW13SecretKeyGenerator;
import it.unisa.dia.gas.crypto.jpbc.fe.abe.gghsw13.params.*;
import it.unisa.dia.gas.crypto.kem.cipher.engines.KEMCipher;
import it.unisa.dia.gas.crypto.kem.cipher.params.KEMCipherDecryptionParameters;
import it.unisa.dia.gas.crypto.kem.cipher.params.KEMCipherEncryptionParameters;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;
import it.unisa.dia.gas.plaf.jpbc.util.concurrent.ExecutorServiceUtils;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.List;

import static it.unisa.dia.gas.crypto.circuit.Gate.Type.*;

public class Example {
    protected KEMCipher kemCipher;
    protected AlgorithmParameterSpec iv;

    protected AsymmetricCipherKeyPair keyPair;


    public Example() throws GeneralSecurityException {
        this.kemCipher = new KEMCipher(
                Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"),
                new GGHSW13KEMEngine()
        );

        // build the initialization vector.  This example is all zeros, but it
        // could be any value or generated using a random number generator.
        iv = new IvParameterSpec(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
    }


    public AsymmetricCipherKeyPair setup(int n) {
        GGHSW13KeyPairGenerator setup = new GGHSW13KeyPairGenerator();
        setup.init(new GGHSW13KeyPairGenerationParameters(
                new SecureRandom(),
                new GGHSW13ParametersGenerator().init(
                        PairingFactory.getPairing("params/mm/ctl13/toy.properties"),
                        n).generateParameters()
        ));

        return (keyPair = setup.generateKeyPair());
    }


    public byte[] initEncryption(String assignment) {
        try {
            return kemCipher.init(
                    true,
                    new KEMCipherEncryptionParameters(
                            128,
                            new GGHSW13EncryptionParameters(
                                    (GGHSW13PublicKeyParameters) keyPair.getPublic(),
                                    assignment
                            )
                    ),
                    iv
            );
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public byte[] encrypt(String message) {
        try {
            return kemCipher.doFinal(message.getBytes());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public CipherParameters keyGen(BooleanCircuit circuit) {
        GGHSW13SecretKeyGenerator keyGen = new GGHSW13SecretKeyGenerator();
        keyGen.init(new GGHSW13SecretKeyGenerationParameters(
                ((GGHSW13PublicKeyParameters) keyPair.getPublic()),
                ((GGHSW13MasterSecretKeyParameters) keyPair.getPrivate()),
                circuit
        ));

        return keyGen.generateKey();
    }

    public byte[] decrypt(CipherParameters secretKey, byte[] encapsulation, byte[] ciphertext) {
        try {
            kemCipher.init(
                    false,
                    new KEMCipherDecryptionParameters(secretKey, encapsulation, 128),
                    iv
            );
            return kemCipher.doFinal(ciphertext);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }



    public static void main(String[] args) {
        Security.addProvider(new BouncyCastleProvider());

        try {
            // Setup
            int n = 4;
            Example engine = new Example();
            engine.setup(n);

            // TODO: Here I want to store (GGHSW13PublicKeyParameters) keyPair.getPublic() and 
            // (GGHSW13MasterSecretKeyParameters) keyPair.getPrivate() in files and later to retrieve from file

            // Encrypt
            String message = "Hello World!!!";
            byte[] encapsulation = engine.initEncryption("1101");
            byte[] ciphertext = engine.encrypt(message);

            BooleanCircuitGate bcg1 = new BooleanCircuitGate(INPUT, 0, 1);

            BooleanCircuitGate[] bcgs = new BooleanCircuitGate[]{
                    new BooleanCircuitGate(INPUT, 0, 1),
                    new BooleanCircuitGate(INPUT, 1, 1),
                    new BooleanCircuitGate(INPUT, 2, 1),
                    new BooleanCircuitGate(INPUT, 3, 1),

                    new BooleanCircuitGate(AND, 4, 2, new int[]{0, 1}),
                    new BooleanCircuitGate(OR, 5, 2, new int[]{2, 3}),

                    new BooleanCircuitGate(AND, 6, 3, new int[]{4, 5}),
            };

            List<BooleanCircuitGate> bcgList = new ArrayList<BooleanCircuitGate>();

            bcgList.add(bcg1);
            bcgList.add(new BooleanCircuitGate(INPUT, 1, 1));
            bcgList.add(new BooleanCircuitGate(INPUT, 2, 1));
            bcgList.add(new BooleanCircuitGate(INPUT, 3, 1));
            bcgList.add(new BooleanCircuitGate(AND, 4, 2, new int[]{0, 1}));
            bcgList.add(new BooleanCircuitGate(OR, 5, 2, new int[]{2, 3}));
            bcgList.add(new BooleanCircuitGate(AND, 6, 3, new int[]{4, 5}));

            // Decrypt
            int q = 3;
            BooleanCircuit circuit = new BooleanCircuit(n, q, 3, bcgList.toArray(new BooleanCircuitGate[bcgList.size()]));

            GGHSW13SecretKeyParameters secretKey = (GGHSW13SecretKeyParameters) engine.keyGen(circuit);

            // TODO: Want to store secretKey in file and later to retrieve from file

            byte[] plaintext = engine.decrypt(secretKey, encapsulation, ciphertext);

            System.out.println(new String(plaintext));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ExecutorServiceUtils.shutdown();
        }
    }

}

推荐答案

生成主密钥和公共参数之后,应该存储它们,以便以后可以实际使用它们. jPBC无法为您提供存储这些密钥的方法.另外,由于键是从org.bouncycastle.crypto.params.AsymmetricKeyParameter继承的,因此您不能使用Java的序列化,因为AsymmetricKeyParameter没有实现Serializable接口. 不能不能工作.

After you generate your master key and the public parameters, you should store them so that you can actually use them later on. jPBC doesn't provide you with a way to store these keys. Also, since the keys inherit from org.bouncycastle.crypto.params.AsymmetricKeyParameter, you can't use Java's serialization, because AsymmetricKeyParameter does not implement the Serializable interface. It doesn't work without.

您将需要自己实现序列化.首先,您必须考虑要序列化的密钥中包含哪种对象.对于GGHSW13MasterSecretKeyParameters类,这是ElementintPairing.

You will need to implement the serialization yourself. First, you have to think about what kind of objects are inside of a key that you want to serialize. In the case of the GGHSW13MasterSecretKeyParameters class, this is an Element, an int and a Pairing.

首先,您必须考虑是否要在序列化密钥中包含Pairing.如果这样做,则必须将其写在开头,以便以后可以使用它反序列化Element.

First, you have to think about whether you want to include the Pairing in the serialized key. If you do, you must write it into the beginning in order to be able to use it later for deserializing the Element.

如果我们假设Pairing实例是恒定的或始终由外部代码提供,则序列化非常容易.您应该在前面写一个格式版本,这样一来您就可以更改格式,而不会丢弃以前所有已序列化的密钥.由于两年前我遇到了一个错误,因此编写元素会有些棘手.基本思想是写元素的字节长度,然后是元素的内容.

If we assume that a Pairing instance is constant or is always provided from outer code, the serialization is pretty easy. You should write a format version to the front, so you can change your formats along the way without throwing away all your previously serialized keys. Writing the element is a little more tricky, because of a bug I encountered 2 years ago. The basic idea is that you write the length of the element's bytes followed by the element's content.

public void serialize(GGHSW13MasterSecretKeyParameters msk, OutputStream out) throws IOException {
    DataOutputStream dOut = new DataOutputStream(out);

    dOut.writeInt(1); // version of the serialized format
    dOut.writeInt(msk.getParameters().getN());

    serialize(msk.getAlpha(), dOut, msk.getParameters().getPairing());
}

public void serialize(Element elem, DataOutputStream dOut, Pairing pairing) throws IOException {
    dOut.writeBoolean(elem == null);
    if (elem == null) {
        return;
    }

    dOut.writeInt(pairing.getFieldIndex(elem.getField()));
    byte[] bytes = elem.toBytes();
    dOut.writeInt(bytes.length);
    dOut.write(bytes);

    // this is a workaround because it.unisa.dia.gas.plaf.jpbc.field.curve.CurveElement does not serialize the infFlag
    dOut.writeBoolean(elem instanceof CurveElement && elem.isZero());
    if (elem instanceof CurveElement && elem.isZero()) {
        throw new IOException("Infinite element detected. They should not happen.");
    }
}

OutputStream可以是FileOutputSteamByteArrayOutputStream之类的东西.

The OutputStream can be something like FileOutputSteam or ByteArrayOutputStream.

反序列化同样容易,但是您需要显式提供Pairing,并且需要确保始终准确地读取 所需的字节数.从数据前面写入的长度int可以知道您请求的字节数.如果不检查该长度是否合理,则可能会引入安全问题,例如拒绝服务漏洞或远程执行代码.

The deserialization is equally easy, but you need to explicitly supply the Pairing and you need to make sure that you always read exactly as many bytes as you requested. The number of bytes that you request is known from the length int that is written in front of the data. If you don't make a check whether that length makes sense, you might introduce a security issue such as a denial of service vulnerability or remote code execution.

public GGHSW13MasterSecretKeyParameters deserialize(InputStream in, Pairing pairing) throws IOException {
    DataInputStream dIn = new DataInputStream(in);

    int version = dIn.readInt();
    if (version != 1) {
        throw new RuntimeException("Unknown key format version: " + version);
    }

    int n = dIn.getInt();
    Element alpha = deserialize(dIn, pairing);

    return new GGHSW13MasterSecretKeyParameters(
            new GGHSW13Parameters(pairing, n),
            alpha
    );
}

public Element deserialize(DataInputStream dIn, Pairing pairing) throws IOException {
    if (dIn.readBoolean()) {
        return null;
    }

    int fieldIndex = dIn.readInt(); // TODO: check if this is in a sensible range
    int length = dIn.readInt(); // TODO: check if this is in a sensible range
    byte[] bytes = new byte[length];
    dIn.readFully(bytes); // throws an exception if there is a premature EOF
    Element e = pairing.getFieldAt(fieldIndex).newElementFromBytes(bytes);

    // this is a workaround because it.unisa.dia.gas.plaf.jpbc.field.curve.CurveElement does not serialize the infFlag
    boolean instOfCurveElementAndInf = dIn.readBoolean();
    if (instOfCurveElementAndInf) {
        //e.setToZero(); // according to the code this simply sets the infFlag to 1
        throw new IOException("The point is infinite. This shouldn't happen.");
    }
    return e;
}

这是一个很小的二进制序列化.还有其他可能性,例如将所有组件编码为字符串并使用JSON.

This is a binary serialization which is sort of small. There are other possibilities like encoding all the components to a string and using JSON for example.

这篇关于从jPBC保存和加载非对称密钥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆