Example usage for org.bouncycastle.crypto BasicAgreement init

List of usage examples for org.bouncycastle.crypto BasicAgreement init

Introduction

In this page you can find the example usage for org.bouncycastle.crypto BasicAgreement init.

Prototype

void init(CipherParameters param);

Source Link

Document

initialise the agreement engine.

Usage

From source file:COSE.Recipient.java

private byte[] ECDH_GenerateSecret(OneKey key) throws CoseException {
    OneKey epk;//from   ww w  .j a  v  a  2 s  . c  o  m

    if (senderKey != null) {
        epk = key;
        key = senderKey;
    } else {
        CBORObject cn;
        cn = findAttribute(HeaderKeys.ECDH_SPK);
        if (cn == null) {
            cn = findAttribute(HeaderKeys.ECDH_EPK);
        }
        if (cn == null)
            throw new CoseException("No second party EC key");
        epk = new OneKey(cn);
    }

    if (key.get(KeyKeys.KeyType.AsCBOR()) != KeyKeys.KeyType_EC2)
        throw new CoseException("Not an EC2 Key");
    if (epk.get(KeyKeys.KeyType.AsCBOR()) != KeyKeys.KeyType_EC2)
        throw new CoseException("Not an EC2 Key");
    if (epk.get(KeyKeys.EC2_Curve.AsCBOR()) != key.get(KeyKeys.EC2_Curve.AsCBOR()))
        throw new CoseException("Curves are not the same");

    X9ECParameters p = epk.GetCurve();
    ECDomainParameters parameters = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH());

    ECPoint pubPoint;

    CBORObject y = epk.get(KeyKeys.EC2_Y.AsCBOR());
    byte[] x = epk.get(KeyKeys.EC2_X.AsCBOR()).GetByteString();
    if (y.getType() == CBORType.Boolean) {
        byte[] X = epk.get(KeyKeys.EC2_X.AsCBOR()).GetByteString();
        byte[] rgb = new byte[X.length + 1];
        System.arraycopy(X, 0, rgb, 1, X.length);
        rgb[0] = (byte) (2 + (y.AsBoolean() ? 1 : 0));
        pubPoint = p.getCurve().decodePoint(rgb);
    } else {
        pubPoint = p.getCurve().createPoint(new BigInteger(1, x), new BigInteger(1, y.GetByteString()));
    }

    ECPublicKeyParameters pub = new ECPublicKeyParameters(pubPoint, parameters);
    ECPrivateKeyParameters priv = new ECPrivateKeyParameters(
            new BigInteger(1, key.get(KeyKeys.EC2_D.AsCBOR()).GetByteString()), parameters);
    BasicAgreement e1 = new ECDHBasicAgreement();
    e1.init(priv);

    BigInteger k1 = e1.calculateAgreement(pub);
    return BigIntegers.asUnsignedByteArray((p.getCurve().getFieldSize() + 7) / 8, k1);
}

From source file:dorkbox.network.connection.registration.remote.RegistrationRemoteHandlerClient.java

License:Apache License

@SuppressWarnings("Duplicates")
void readClient(final Channel channel, final Registration registration, final String type,
        final MetaChannel metaChannel) {
    final InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();

    //  IN: session ID + public key + ecc parameters (which are a nonce. the SERVER defines what these are)
    // OUT: remote ECDH shared payload
    if (metaChannel.aesKey == null && registration.publicKey != null) {
        // whoa! Didn't send valid public key info!
        if (invalidPublicKey(registration, type)) {
            shutdown(channel, registration.sessionID);
            return;
        }//from   w ww. jav a 2 s. com

        // want to validate the public key used! This is similar to how SSH works, in that once we use a public key, we want to validate
        // against that ip-address::key pair, so we can better protect against MITM/spoof attacks.
        if (invalidRemoteAddress(metaChannel, registration, type, remoteAddress)) {
            // whoa! abort since something messed up! (log and recording if key changed happens inside of validate method)
            shutdown(channel, registration.sessionID);
            return;
        }

        // save off remote public key. This is ALWAYS the same, where the ECDH changes every time...
        metaChannel.publicKey = registration.publicKey;

        // It is OK that we generate a new ECC keypair for ECDHE every time that we connect from the client.
        // The server rotates keys every XXXX seconds, since this step is expensive (and the server is the 'trusted' endpoint).
        metaChannel.ecdhKey = CryptoECC.generateKeyPair(eccSpec, registrationWrapper.getSecureRandom());

        Registration outboundRegister = new Registration(metaChannel.sessionId);

        Output output = new Output(1024);
        EccPublicKeySerializer.write(output, (ECPublicKeyParameters) metaChannel.ecdhKey.getPublic());
        outboundRegister.payload = output.toBytes();

        channel.writeAndFlush(outboundRegister);
        return;
    }

    //  IN: remote ECDH shared payload
    // OUT: hasMore=true if we have more registrations to do, false otherwise
    if (metaChannel.aesKey == null) {
        /*
         * Diffie-Hellman-Merkle key exchange for the AES key
         * http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
         */
        byte[] ecdhPubKeyBytes = Arrays.copyOfRange(registration.payload, 0, registration.payload.length);
        ECPublicKeyParameters ecdhPubKey;
        try {
            ecdhPubKey = EccPublicKeySerializer.read(new Input(ecdhPubKeyBytes));
        } catch (KryoException e) {
            logger.error("Invalid decode of ECDH public key. Aborting.");
            shutdown(channel, registration.sessionID);
            return;
        }

        BasicAgreement agreement = new ECDHCBasicAgreement();
        agreement.init(metaChannel.ecdhKey.getPrivate());
        BigInteger shared = agreement.calculateAgreement(ecdhPubKey);

        // now we setup our AES key based on our shared secret! (from ECDH)
        // the shared secret is different each time a connection is made
        byte[] keySeed = shared.toByteArray();

        SHA384Digest sha384 = new SHA384Digest();
        byte[] digest = new byte[sha384.getDigestSize()];
        sha384.update(keySeed, 0, keySeed.length);
        sha384.doFinal(digest, 0);

        metaChannel.aesKey = Arrays.copyOfRange(digest, 0, 32); // 256bit keysize (32 bytes)
        metaChannel.aesIV = Arrays.copyOfRange(digest, 32, 44); // 96bit blocksize (12 bytes) required by AES-GCM

        if (invalidAES(metaChannel)) {
            // abort if something messed up!
            shutdown(channel, registration.sessionID);
            return;
        }

        Registration outboundRegister = new Registration(metaChannel.sessionId);

        // do we have any more registrations?
        outboundRegister.hasMore = registrationWrapper.hasMoreRegistrations();
        channel.writeAndFlush(outboundRegister);

        // wait for ack from the server before registering the next protocol
        return;
    }

    // IN: upgrade=true if we must upgrade this connection
    if (registration.upgrade) {
        // this pipeline can now be marked to be upgraded

        // upgrade the connection to an encrypted connection
        // this pipeline encoder/decoder can now be upgraded, and the "connection" added
        upgradeEncoders(channel, metaChannel, remoteAddress);
        upgradeDecoders(channel, metaChannel);
    }

    // IN: hasMore=true if we have more registrations to do, false otherwise
    if (registration.hasMore) {
        logger.trace("Starting another protocol registration");
        metaChannel.totalProtocols.incrementAndGet();
        registrationWrapper.startNextProtocolRegistration();
        return;
    }

    //
    //
    // we only get this when we are 100% done with the registration of all connection types.
    //
    //

    if (!registration.upgraded) {
        // setup the pipeline with the real connection
        upgradePipeline(metaChannel, remoteAddress);

        // we don't verify anything on the CLIENT. We only verify on the server.
        // we don't support registering NEW classes after the client starts.
        if (!registrationWrapper.initClassRegistration(channel, registration)) {
            // abort if something messed up!
            shutdown(channel, registration.sessionID);
        }

        return;
    }

    // IN: upgraded=true this means we are ready to connect, and the server is done with it's onConnect calls
    //              we defer the messages until after our own onConnect() is called...

    // we have to wait for ALL messages to be received, this way we can prevent out-of-order oddities...
    int protocolsRemaining = metaChannel.totalProtocols.decrementAndGet();
    if (protocolsRemaining > 0) {
        logger.trace("{} done. Waiting for {} more protocols registrations to arrive...", type,
                protocolsRemaining);
        return;
    }

    // remove the ConnectionWrapper (that was used to upgrade the connection) and cleanup the pipeline
    // always wait until AFTER the server calls "onConnect", then we do this
    cleanupPipeline(metaChannel, new Runnable() {
        @Override
        public void run() {
            // this method runs after the "onConnect()" runs and only after all of the channels have be correctly updated

            // get all of the out of order messages that we missed
            List<Object> messages = new LinkedList<Object>();

            if (metaChannel.tcpChannel != null) {
                List<Object> list = getOutOfOrderMessagesAndReset(metaChannel.tcpChannel);
                if (list != null) {
                    logger.trace("Getting deferred TCP messages: {}", list.size());
                    messages.addAll(list);
                }
            }

            if (metaChannel.udpChannel != null) {
                List<Object> list = getOutOfOrderMessagesAndReset(metaChannel.udpChannel);
                if (list != null) {
                    logger.trace("Getting deferred UDP messages: {}", list.size());
                    messages.addAll(list);
                }
            }

            // now call 'onMessage' in the connection object with our messages!
            try {
                ConnectionImpl connection = (ConnectionImpl) metaChannel.connection;

                for (Object message : messages) {
                    logger.trace("    deferred onMessage({}, {})", connection.id(), message);
                    try {
                        connection.channelRead(null, message);
                    } catch (Exception e) {
                        logger.error("Error running deferred messages!", e);
                    }
                }

            } catch (Exception e) {
                logger.error("Error initialising deferred messages!", e);
            }
        }
    });
}

From source file:dorkbox.network.connection.registration.remote.RegistrationRemoteHandlerServer.java

License:Apache License

@SuppressWarnings("Duplicates")
void readServer(final ChannelHandlerContext context, final Channel channel, final Registration registration,
        final String type, final MetaChannel metaChannel) {
    final InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();

    //  IN: session ID == 0 (start of new connection)
    // OUT: session ID + public key + ecc parameters (which are a nonce. the SERVER defines what these are)
    if (registration.sessionID == 0) {
        // whoa! Didn't send valid public key info!
        if (invalidPublicKey(registration, type)) {
            shutdown(channel, registration.sessionID);
            return;
        }/*from w ww  . j av a2  s .c  o  m*/

        // want to validate the public key used! This is similar to how SSH works, in that once we use a public key, we want to validate
        // against that ip-address::key pair, so we can better protect against MITM/spoof attacks.
        if (invalidRemoteAddress(metaChannel, registration, type, remoteAddress)) {
            // whoa! abort since something messed up! (log and recording if key changed happens inside of validate method)
            shutdown(channel, registration.sessionID);
            return;
        }

        // save off remote public key. This is ALWAYS the same, where the ECDH changes every time...
        metaChannel.publicKey = registration.publicKey;

        // tell the client to continue it's registration process.
        Registration outboundRegister = new Registration(metaChannel.sessionId);
        outboundRegister.publicKey = registrationWrapper.getPublicKey();
        outboundRegister.eccParameters = CryptoECC
                .generateSharedParameters(registrationWrapper.getSecureRandom());

        channel.writeAndFlush(outboundRegister);
        return;
    }

    //  IN: remote ECDH shared payload
    // OUT: server ECDH shared payload
    if (metaChannel.aesKey == null) {
        /*
         * Diffie-Hellman-Merkle key exchange for the AES key
         * http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
         */

        // the ECDH key will ROTATE every 10 minutes, since generating it for EVERY connection is expensive
        // and since we are combining ECDHE+ECC public/private keys for each connection, other
        // connections cannot break someone else's connection, since they are still protected by their own private keys.
        metaChannel.ecdhKey = getEchdKeyOnRotate(registrationWrapper.getSecureRandom());

        byte[] ecdhPubKeyBytes = java.util.Arrays.copyOfRange(registration.payload, 0,
                registration.payload.length);
        ECPublicKeyParameters ecdhPubKey;
        try {
            ecdhPubKey = EccPublicKeySerializer.read(new Input(ecdhPubKeyBytes));
        } catch (KryoException e) {
            logger.error("Invalid decode of ECDH public key. Aborting.");
            shutdown(channel, registration.sessionID);
            return;
        }

        BasicAgreement agreement = new ECDHCBasicAgreement();
        agreement.init(metaChannel.ecdhKey.getPrivate());
        BigInteger shared = agreement.calculateAgreement(ecdhPubKey);

        // now we setup our AES key based on our shared secret! (from ECDH)
        // the shared secret is different each time a connection is made
        byte[] keySeed = shared.toByteArray();

        SHA384Digest sha384 = new SHA384Digest();
        byte[] digest = new byte[sha384.getDigestSize()];
        sha384.update(keySeed, 0, keySeed.length);
        sha384.doFinal(digest, 0);

        metaChannel.aesKey = Arrays.copyOfRange(digest, 0, 32); // 256bit keysize (32 bytes)
        metaChannel.aesIV = Arrays.copyOfRange(digest, 32, 44); // 96bit blocksize (12 bytes) required by AES-GCM

        if (invalidAES(metaChannel)) {
            // abort if something messed up!
            shutdown(channel, registration.sessionID);
            return;
        }

        Registration outboundRegister = new Registration(metaChannel.sessionId);

        Output output = new Output(1024);
        EccPublicKeySerializer.write(output, (ECPublicKeyParameters) metaChannel.ecdhKey.getPublic());
        outboundRegister.payload = output.toBytes();

        channel.writeAndFlush(outboundRegister);
        return;
    }

    // NOTE: if we have more registrations, we will "bounce back" that status so the client knows what to do.
    // IN: hasMore=true if we have more registrations to do, false otherwise

    // ALWAYS upgrade the connection at this point.
    // IN: upgraded=false if we haven't upgraded to encryption yet (this will always be the case right after encryption is setup)

    if (!registration.upgraded) {
        // upgrade the connection to an encrypted connection
        registration.upgrade = true;
        upgradeDecoders(channel, metaChannel);

        // bounce back to the client so it knows we received it
        channel.write(registration);

        // this pipeline encoder/decoder can now be upgraded, and the "connection" added
        upgradeEncoders(channel, metaChannel, remoteAddress);

        if (!registration.hasMore) {
            // we only get this when we are 100% done with the registration of all connection types.

            // setup the pipeline with the real connection
            upgradePipeline(metaChannel, remoteAddress);
        }

        channel.flush();
        return;
    }

    // the client will send their class registration data. VERIFY IT IS CORRECT!
    STATE state = registrationWrapper.verifyClassRegistration(metaChannel, registration);
    if (state == STATE.ERROR) {
        // abort! There was an error
        shutdown(channel, registration.sessionID);
        return;
    } else if (state == STATE.WAIT) {
        return;
    }
    // else, continue.

    //
    //
    // we only get this when we are 100% done with the registration of all connection types.
    //      the context is the LAST protocol to be registered
    //
    //

    // remove the ConnectionWrapper (that was used to upgrade the connection) and cleanup the pipeline
    cleanupPipeline(metaChannel, new Runnable() {
        @Override
        public void run() {
            // this method runs after the "onConnect()" runs and only after all of the channels have be correctly updated

            // this tells the client we are ready to connect (we just bounce back the original message over ALL protocols)
            if (metaChannel.tcpChannel != null) {
                logger.trace("Sending TCP upgraded command");
                Registration reg = new Registration(registration.sessionID);
                reg.upgraded = true;
                metaChannel.tcpChannel.writeAndFlush(reg);
            }

            if (metaChannel.udpChannel != null) {
                logger.trace("Sending UDP upgraded command");
                Registration reg = new Registration(registration.sessionID);
                reg.upgraded = true;
                metaChannel.udpChannel.writeAndFlush(reg);
            }
        }
    });
}

From source file:dorkbox.util.crypto.EccTest.java

License:Apache License

@Test
public void Ecdh() throws IOException {
    // test DH key exchange
    SecureRandom secureRandom = new SecureRandom();

    AsymmetricCipherKeyPair key1 = CryptoECC.generateKeyPair(CryptoECC.default_curve, secureRandom);
    AsymmetricCipherKeyPair key2 = CryptoECC.generateKeyPair(CryptoECC.default_curve, secureRandom);

    BasicAgreement e1 = new ECDHCBasicAgreement();
    BasicAgreement e2 = new ECDHCBasicAgreement();

    e1.init(key1.getPrivate());
    e2.init(key2.getPrivate());//from ww w.  jav a  2 s .  c om

    BigInteger k1 = e1.calculateAgreement(key2.getPublic());
    BigInteger k2 = e2.calculateAgreement(key1.getPublic());

    if (!k1.equals(k2)) {
        fail("ECDHC cipher test failed");
    }
}

From source file:me.grapebaba.hyperledger.fabric.Crypto.java

License:Apache License

public ByteString eciesDecrypt(PrivateKey recipientPrivateKey, ByteString cipherText) {
    BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) recipientPrivateKey;
    ECNamedCurveSpec ecNamedCurveSpec = (ECNamedCurveSpec) bcecPrivateKey.getParams();
    int level = SecurityLevel.from(ecNamedCurveSpec.getName()).size();

    //cipherText = ephemeralPubKeyBytes + encryptedTokBytes + macBytes
    //ephemeralPubKeyBytes = first ((384+7)/8)*2 + 1 bytes = first 97 bytes
    //hmac is sha3_384 = 48 bytes or sha3_256 = 32 bytes
    int ephemeralPubKeyLength = ((level + 7) / 8) * 2 + 1;
    int hmacLength = level >> 3;
    int cipherTextLength = cipherText.size();

    if (cipherTextLength <= ephemeralPubKeyLength + hmacLength)
        throw new RuntimeException(String.format("Illegal cipherText length: %d must be > %d", cipherTextLength,
                ephemeralPubKeyLength + hmacLength));

    ByteString ephemeralPubKey = cipherText.substring(0, ephemeralPubKeyLength);
    ByteString encryptedContent = cipherText.substring(ephemeralPubKeyLength, cipherTextLength - hmacLength);
    ByteString hmac = cipherText.substring(cipherTextLength - hmacLength);

    ECPrivateKeyParameters ecdhPrivateKeyParameters;
    try {/*from   w w  w  .  j  a va 2  s  .  co  m*/
        ecdhPrivateKeyParameters = (ECPrivateKeyParameters) (PrivateKeyFactory
                .createKey(bcecPrivateKey.getEncoded()));
    } catch (IOException e) {
        logger.error("ECIES decrypt load private key exception", e);
        throw new RuntimeException(e);
    }
    ECDomainParameters ecDomainParameters = ecdhPrivateKeyParameters.getParameters();
    ECCurve ecCurve = ecDomainParameters.getCurve();
    ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(
            ecCurve.decodePoint(ephemeralPubKey.toByteArray()), ecDomainParameters);
    BasicAgreement agree = new ECDHBasicAgreement();
    agree.init(ecdhPrivateKeyParameters);
    byte[] keyAgreement = agree.calculateAgreement(ecPublicKeyParameters).toByteArray();

    HKDFParameters hkdfParameters = new HKDFParameters(keyAgreement, null, null);
    HKDFBytesGenerator hkdfBytesGenerator = new HKDFBytesGenerator(digest);
    hkdfBytesGenerator.init(hkdfParameters);
    byte[] hkdfOutputBytes = new byte[AESKEY_LENGTH + HMACKEY_LENGTH];
    hkdfBytesGenerator.generateBytes(hkdfOutputBytes, 0, AESKEY_LENGTH + HMACKEY_LENGTH);
    ByteString hkdfOutput = ByteString.copyFrom(hkdfOutputBytes);
    ByteString aesKey = hkdfOutput.substring(0, AESKEY_LENGTH);
    ByteString hmacKey = hkdfOutput.substring(AESKEY_LENGTH, AESKEY_LENGTH + HMACKEY_LENGTH);
    HMac hMac = new HMac(digest);
    hMac.init(new KeyParameter(hmacKey.toByteArray()));
    hMac.update(encryptedContent.toByteArray(), 0, encryptedContent.size());
    byte[] recoveredHmac = new byte[hMac.getMacSize()];
    hMac.doFinal(recoveredHmac, 0);
    if (!MessageDigest.isEqual(hmac.toByteArray(), recoveredHmac)) {
        throw new RuntimeException("HMAC verify failed");
    }

    CFBBlockCipher aesCipher = new CFBBlockCipher(new AESEngine(), BLOCK_BIT_SIZE);
    ByteString iv = encryptedContent.substring(0, IV_LENGTH);
    CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(aesKey.toByteArray()), iv.toByteArray());
    aesCipher.init(false, ivAndKey);
    byte[] decryptedBytes = new byte[500];
    aesCipher.decryptBlock(encryptedContent.substring(IV_LENGTH).toByteArray(), 0, decryptedBytes, 0);
    return ByteString.copyFrom(decryptedBytes);
}