public byte[] getRemotePublicKey() throws CryptoManagerException {

    if (remotePubKey == null) {

      throw (new CryptoManagerException("key not yet available"));
    }

    return (CryptoECCUtils.keyToRawdata(remotePubKey));
  }
  /** @param myIdent keypair representing our current identity */
  CryptoSTSEngineImpl(PublicKey _myPub, PrivateKey _myPriv) throws CryptoManagerException {

    myPublicKey = _myPub;
    myPrivateKey = _myPriv;

    ephemeralKeyPair = CryptoECCUtils.createKeys();

    try {
      ecDH = new InternalDH();

      // ecDH = KeyAgreement.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME);

      ecDH.init(ephemeralKeyPair.getPrivate());

    } catch (Exception e) {

      throw new CryptoManagerException("Couldn't initialize crypto handshake", e);
    }
  }
  public void putMessage(ByteBuffer message, boolean keys) throws CryptoManagerException {

    // System.out.println( "put( " + keys + ") " + this );

    try {
      int version = getInt(message, 255);

      if (version != VERSION) {

        throw (new CryptoManagerException("invalid version (" + version + ")"));
      }

      if (keys) {

        if (sharedSecret != null) {

          throw (new CryptoManagerException("phase error: keys already received"));
        }

        final byte[] rawRemoteOtherPubkey = getBytes(message, 65535);

        final byte[] rawRemoteEphemeralPubkey = getBytes(message, 65535);

        final byte[] remoteSig = getBytes(message, 65535);

        final byte[] pad = getBytes(message, 65535);

        remotePubKey = CryptoECCUtils.rawdataToPubkey(rawRemoteOtherPubkey);

        Signature check = CryptoECCUtils.getSignature(remotePubKey);

        check.update(rawRemoteOtherPubkey);

        check.update(rawRemoteEphemeralPubkey);

        if (check.verify(remoteSig)) {

          ecDH.doPhase(CryptoECCUtils.rawdataToPubkey(rawRemoteEphemeralPubkey), true);

          sharedSecret = ecDH.generateSecret();

        } else {

          throw (new CryptoManagerException("Signature check failed"));
        }

      } else {

        if (sharedSecret == null) {

          throw (new CryptoManagerException("phase error: keys not received"));
        }

        final byte[] IV = getBytes(message, 65535);

        final byte[] remoteSig = getBytes(message, 65535);

        Signature check = CryptoECCUtils.getSignature(remotePubKey);

        check.update(IV);

        check.update(sharedSecret);

        if (!check.verify(remoteSig)) {

          throw (new CryptoManagerException("Signature check failed"));
        }
      }
    } catch (CryptoManagerException e) {

      throw (e);

    } catch (Throwable e) {

      throw (new CryptoManagerException("Failed to generate message"));
    }
  }
  public void getMessage(ByteBuffer buffer, boolean keys) throws CryptoManagerException {

    // System.out.println( "get( " + keys + ") " + this );

    try {
      putInt(buffer, VERSION, 255);

      SecureRandom random = SecureRandom.getInstance("SHA1PRNG");

      Signature sig = CryptoECCUtils.getSignature(myPrivateKey);

      if (keys) {

        final byte[] rawMyPubkey = CryptoECCUtils.keyToRawdata(myPublicKey);

        final byte[] rawEphemeralPubkey = CryptoECCUtils.keyToRawdata(ephemeralKeyPair.getPublic());

        sig.update(rawMyPubkey);

        sig.update(rawEphemeralPubkey);

        final byte[] rawSign = sig.sign();

        final byte[] pad = new byte[random.nextInt(32)];

        random.nextBytes(pad);

        putBytes(buffer, rawMyPubkey, 65535);

        putBytes(buffer, rawEphemeralPubkey, 65535);

        putBytes(buffer, rawSign, 65535);

        putBytes(buffer, pad, 65535);

      } else {

        if (sharedSecret == null) {

          throw (new CryptoManagerException("phase error: keys not received"));
        }

        final byte[] IV = new byte[20 + random.nextInt(32)];

        random.nextBytes(IV);

        sig.update(IV);

        sig.update(sharedSecret);

        final byte[] rawSig = sig.sign();

        putBytes(buffer, IV, 65535);

        putBytes(buffer, rawSig, 65535);
      }
    } catch (CryptoManagerException e) {

      throw (e);

    } catch (Throwable e) {

      throw (new CryptoManagerException("Failed to generate message"));
    }
  }