예제 #1
0
파일: ECCurve.java 프로젝트: Relvl/bc-java
  /**
   * Decode a point on this curve from its ASN.1 encoding. The different encodings are taken account
   * of, including point compression for <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
   *
   * @return The decoded point.
   */
  public ECPoint decodePoint(byte[] encoded) {
    ECPoint p = null;
    int expectedLength = (getFieldSize() + 7) / 8;

    switch (encoded[0]) {
      case 0x00: // infinity
        {
          if (encoded.length != 1) {
            throw new IllegalArgumentException("Incorrect length for infinity encoding");
          }

          p = getInfinity();
          break;
        }
      case 0x02: // compressed
      case 0x03: // compressed
        {
          if (encoded.length != (expectedLength + 1)) {
            throw new IllegalArgumentException("Incorrect length for compressed encoding");
          }

          int yTilde = encoded[0] & 1;
          BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);

          p = decompressPoint(yTilde, X);
          break;
        }
      case 0x04: // uncompressed
      case 0x06: // hybrid
      case 0x07: // hybrid
        {
          if (encoded.length != (2 * expectedLength + 1)) {
            throw new IllegalArgumentException("Incorrect length for uncompressed/hybrid encoding");
          }

          BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
          BigInteger Y =
              BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength);

          p = createPoint(X, Y);
          break;
        }
      default:
        throw new IllegalArgumentException(
            "Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
    }

    return p;
  }
예제 #2
0
  private void checkMessage(
      Signature sgr, PrivateKey sKey, PublicKey vKey, byte[] message, byte[] sig)
      throws InvalidKeyException, SignatureException {
    byte[] kData =
        BigIntegers.asUnsignedByteArray(
            new BigInteger(
                "700000017569056646655505781757157107570501575775705779575555657156756655"));

    SecureRandom k = new FixedSecureRandom(kData);

    sgr.initSign(sKey, k);

    sgr.update(message);

    byte[] sigBytes = sgr.sign();

    if (!Arrays.areEqual(sigBytes, sig)) {
      fail(new String(message) + " signature incorrect");
    }

    sgr.initVerify(vKey);

    sgr.update(message);

    if (!sgr.verify(sigBytes)) {
      fail(new String(message) + " verification failed");
    }
  }
예제 #3
0
  /**
   * Computes the simulator computation.
   *
   * @param input MUST be an instance of SigmaDHCommonInput.
   * @param challenge
   * @return the output of the computation - (a, e, z).
   * @throws CheatAttemptException if the received challenge's length is not equal to the soundness
   *     parameter.
   * @throws IllegalArgumentException if the given input is not an instance of SigmaDHCommonInput.
   */
  public SigmaSimulatorOutput simulate(SigmaCommonInput input, byte[] challenge)
      throws CheatAttemptException {
    // check the challenge validity.
    if (!checkChallengeLength(challenge)) {
      throw new CheatAttemptException(
          "the length of the given challenge is differ from the soundness parameter");
    }
    if (!(input instanceof SigmaDHCommonInput)) {
      throw new IllegalArgumentException("the given input must be an instance of SigmaDHInput");
    }
    SigmaDHCommonInput dhInput = ((SigmaDHCommonInput) input);

    // Sample a random z <- Zq
    BigInteger z = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, random);

    // Compute a = g^z*u^(-e) (where -e here means -e mod q)
    GroupElement gToZ = dlog.exponentiate(dlog.getGenerator(), z);
    BigInteger e = new BigInteger(1, challenge);
    BigInteger minusE = dlog.getOrder().subtract(e);
    GroupElement uToE = dlog.exponentiate(dhInput.getU(), minusE);
    GroupElement a = dlog.multiplyGroupElements(gToZ, uToE);

    // Compute b = h^z*v^(-e) (where -e here means -e mod q)
    GroupElement hToZ = dlog.exponentiate(dhInput.getH(), z);
    GroupElement vToE = dlog.exponentiate(dhInput.getV(), minusE);
    GroupElement b = dlog.multiplyGroupElements(hToZ, vToE);

    // Output ((a,b),e,z).
    return new SigmaDHSimulatorOutput(
        new SigmaDHMsg(a.generateSendableData(), b.generateSendableData()),
        challenge,
        new SigmaBIMsg(z));
  }
 protected byte[] calculateDHBasicAgreement(
     DHPublicKeyParameters publicKey, DHPrivateKeyParameters privateKey) {
   DHBasicAgreement dhAgree = new DHBasicAgreement();
   dhAgree.init(dhAgreeClientPrivateKey);
   BigInteger agreement = dhAgree.calculateAgreement(dhAgreeServerPublicKey);
   return BigIntegers.asUnsignedByteArray(agreement);
 }
  protected void generateEphemeralClientKeyExchange(DHParameters dhParams, OutputStream os)
      throws IOException {
    AsymmetricCipherKeyPair dhAgreeClientKeyPair = generateDHKeyPair(dhParams);
    this.dhAgreeClientPrivateKey = (DHPrivateKeyParameters) dhAgreeClientKeyPair.getPrivate();

    BigInteger Yc = ((DHPublicKeyParameters) dhAgreeClientKeyPair.getPublic()).getY();
    byte[] keData = BigIntegers.asUnsignedByteArray(Yc);
    TlsUtils.writeUint24(keData.length + 2, os);
    TlsUtils.writeOpaque16(keData, os);
  }
예제 #6
0
  private static BigInteger calculateGenerator_FIPS186_2(
      BigInteger p, BigInteger q, SecureRandom r) {
    BigInteger e = p.subtract(ONE).divide(q);
    BigInteger pSub2 = p.subtract(TWO);

    for (; ; ) {
      BigInteger h = BigIntegers.createRandomInRange(TWO, pSub2, r);
      BigInteger g = h.modPow(e, p);
      if (g.bitLength() > 1) {
        return g;
      }
    }
  }
예제 #7
0
  /**
   * Calculate a zero knowledge proof of x using Schnorr's signature. The returned array has two
   * elements {g^v, r = v-x*h} for x.
   */
  public static BigInteger[] calculateZeroKnowledgeProof(
      BigInteger p,
      BigInteger q,
      BigInteger g,
      BigInteger gx,
      BigInteger x,
      String participantId,
      Digest digest,
      SecureRandom random) {
    BigInteger[] zeroKnowledgeProof = new BigInteger[2];

    /* Generate a random v, and compute g^v */
    BigInteger vMin = ZERO;
    BigInteger vMax = q.subtract(ONE);
    BigInteger v = BigIntegers.createRandomInRange(vMin, vMax, random);

    BigInteger gv = g.modPow(v, p);
    BigInteger h = calculateHashForZeroKnowledgeProof(g, gv, gx, participantId, digest); // h

    zeroKnowledgeProof[0] = gv;
    zeroKnowledgeProof[1] = v.subtract(x.multiply(h)).mod(q); // r = v-x*h

    return zeroKnowledgeProof;
  }
예제 #8
0
  private void testECDSA239bitBinary(String algorithm, DERObjectIdentifier oid) throws Exception {
    BigInteger r =
        new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
    BigInteger s =
        new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174");

    byte[] kData =
        BigIntegers.asUnsignedByteArray(
            new BigInteger(
                "171278725565216523967285789236956265265265235675811949404040041670216363"));

    SecureRandom k = new FixedSecureRandom(kData);

    ECCurve curve =
        new ECCurve.F2m(
            239, // m
            36, // k
            new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
            new BigInteger(
                "790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b

    ECParameterSpec params =
        new ECParameterSpec(
            curve,
            curve.decodePoint(
                Hex.decode(
                    "0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
            new BigInteger(
                "220855883097298041197912187592864814557886993776713230936715041207411783"), // n
            BigInteger.valueOf(4)); // h

    ECPrivateKeySpec priKeySpec =
        new ECPrivateKeySpec(
            new BigInteger(
                "145642755521911534651321230007534120304391871461646461466464667494947990"), // d
            params);

    ECPublicKeySpec pubKeySpec =
        new ECPublicKeySpec(
            curve.decodePoint(
                Hex.decode(
                    "045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
            params);

    Signature sgr = Signature.getInstance(algorithm, "BC");
    KeyFactory f = KeyFactory.getInstance("ECDSA", "BC");
    PrivateKey sKey = f.generatePrivate(priKeySpec);
    PublicKey vKey = f.generatePublic(pubKeySpec);
    byte[] message = new byte[] {(byte) 'a', (byte) 'b', (byte) 'c'};

    sgr.initSign(sKey, k);

    sgr.update(message);

    byte[] sigBytes = sgr.sign();

    sgr = Signature.getInstance(oid.getId(), "BC");

    sgr.initVerify(vKey);

    sgr.update(message);

    if (!sgr.verify(sigBytes)) {
      fail("239 Bit EC RIPEMD160 verification failed");
    }
  }
예제 #9
0
  /**
   * X9.62 - 1998,<br>
   * J.3.2, Page 155, ECDSA over the field Fp<br>
   * an example with 239 bit prime
   */
  private void testECDSA239bitPrime() throws Exception {
    BigInteger r =
        new BigInteger("308636143175167811492622547300668018854959378758531778147462058306432176");
    BigInteger s =
        new BigInteger("323813553209797357708078776831250505931891051755007842781978505179448783");

    byte[] kData =
        BigIntegers.asUnsignedByteArray(
            new BigInteger(
                "700000017569056646655505781757157107570501575775705779575555657156756655"));

    SecureRandom k = new FixedSecureRandom(kData);

    ECCurve curve =
        new ECCurve.Fp(
            new BigInteger(
                "883423532389192164791648750360308885314476597252960362792450860609699839"), // q
            new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
            new BigInteger(
                "6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b

    ECParameterSpec spec =
        new ECParameterSpec(
            curve,
            curve.decodePoint(
                Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
            new BigInteger(
                "883423532389192164791648750360308884807550341691627752275345424702807307")); // n

    ECPrivateKeySpec priKey =
        new ECPrivateKeySpec(
            new BigInteger(
                "876300101507107567501066130761671078357010671067781776716671676178726717"), // d
            spec);

    ECPublicKeySpec pubKey =
        new ECPublicKeySpec(
            curve.decodePoint(
                Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
            spec);

    Signature sgr = Signature.getInstance("ECDSA", "BC");
    KeyFactory f = KeyFactory.getInstance("ECDSA", "BC");
    PrivateKey sKey = f.generatePrivate(priKey);
    PublicKey vKey = f.generatePublic(pubKey);

    sgr.initSign(sKey, k);

    byte[] message = new byte[] {(byte) 'a', (byte) 'b', (byte) 'c'};

    sgr.update(message);

    byte[] sigBytes = sgr.sign();

    sgr.initVerify(vKey);

    sgr.update(message);

    if (!sgr.verify(sigBytes)) {
      fail("239 Bit EC verification failed");
    }

    BigInteger[] sig = derDecode(sigBytes);

    if (!r.equals(sig[0])) {
      fail(
          "r component wrong."
              + System.getProperty("line.separator")
              + " expecting: "
              + r
              + System.getProperty("line.separator")
              + " got      : "
              + sig[0]);
    }

    if (!s.equals(sig[1])) {
      fail(
          "s component wrong."
              + System.getProperty("line.separator")
              + " expecting: "
              + s
              + System.getProperty("line.separator")
              + " got      : "
              + sig[1]);
    }
  }
예제 #10
0
 public byte[] getEncoded() {
   return BigIntegers.asUnsignedByteArray((getFieldSize() + 7) / 8, toBigInteger());
 }
예제 #11
0
 /**
  * Return a value that can be used as x2 or x4 during round 1.
  *
  * <p>
  *
  * <p>The returned value is a random value in the range <tt>[1, q-1]</tt>.
  */
 public static BigInteger generateX2(BigInteger q, SecureRandom random) {
   BigInteger min = ONE;
   BigInteger max = q.subtract(ONE);
   return BigIntegers.createRandomInRange(min, max, random);
 }
예제 #12
0
 private static void updateMac(Mac mac, BigInteger bigInteger) {
   byte[] byteArray = BigIntegers.asUnsignedByteArray(bigInteger);
   mac.update(byteArray, 0, byteArray.length);
   Arrays.fill(byteArray, (byte) 0);
 }
예제 #13
0
 private static void updateDigestIncludingSize(Digest digest, BigInteger bigInteger) {
   byte[] byteArray = BigIntegers.asUnsignedByteArray(bigInteger);
   digest.update(intToByteArray(byteArray.length), 0, 4);
   digest.update(byteArray, 0, byteArray.length);
   Arrays.fill(byteArray, (byte) 0);
 }
  /**
   * @param message
   * @param pointer
   * @return
   */
  @Override
  public int parseMessageAction(byte[] message, int pointer) {
    if (message[pointer] != HandshakeMessageType.SERVER_KEY_EXCHANGE.getValue()) {
      throw new InvalidMessageTypeException(HandshakeMessageType.SERVER_KEY_EXCHANGE);
    }
    protocolMessage.setType(message[pointer]);

    int currentPointer = pointer + HandshakeByteLength.MESSAGE_TYPE;
    int nextPointer = currentPointer + HandshakeByteLength.MESSAGE_TYPE_LENGTH;
    int length =
        ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer));
    protocolMessage.setLength(length);

    currentPointer = nextPointer;
    nextPointer = currentPointer + HandshakeByteLength.DH_PARAM_LENGTH;
    int pLength =
        ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer));
    protocolMessage.setpLength(pLength);

    currentPointer = nextPointer;
    nextPointer = currentPointer + protocolMessage.getpLength().getValue();
    BigInteger p = new BigInteger(1, Arrays.copyOfRange(message, currentPointer, nextPointer));
    protocolMessage.setP(p);

    currentPointer = nextPointer;
    nextPointer = currentPointer + HandshakeByteLength.DH_PARAM_LENGTH;
    int gLength =
        ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer));
    protocolMessage.setgLength(gLength);

    currentPointer = nextPointer;
    nextPointer = currentPointer + protocolMessage.getgLength().getValue();
    BigInteger g = new BigInteger(1, Arrays.copyOfRange(message, currentPointer, nextPointer));
    protocolMessage.setG(g);

    currentPointer = nextPointer;
    nextPointer = currentPointer + HandshakeByteLength.DH_PARAM_LENGTH;
    int publicKeyLength =
        ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer));
    protocolMessage.setPublicKeyLength(publicKeyLength);

    currentPointer = nextPointer;
    nextPointer = currentPointer + protocolMessage.getPublicKeyLength().getValue();
    BigInteger publicKey =
        new BigInteger(1, Arrays.copyOfRange(message, currentPointer, nextPointer));
    protocolMessage.setPublicKey(publicKey);

    byte[] dhParams =
        ArrayConverter.concatenate(
            ArrayConverter.intToBytes(
                protocolMessage.getpLength().getValue(), HandshakeByteLength.DH_PARAM_LENGTH),
            BigIntegers.asUnsignedByteArray(protocolMessage.getP().getValue()),
            ArrayConverter.intToBytes(
                protocolMessage.getgLength().getValue(), HandshakeByteLength.DH_PARAM_LENGTH),
            BigIntegers.asUnsignedByteArray(protocolMessage.getG().getValue()),
            ArrayConverter.intToBytes(
                protocolMessage.getPublicKeyLength().getValue(),
                HandshakeByteLength.DH_PARAM_LENGTH),
            BigIntegers.asUnsignedByteArray(protocolMessage.getPublicKey().getValue()));
    InputStream is = new ByteArrayInputStream(dhParams);

    try {
      ServerDHParams publicKeyParameters = ServerDHParams.parse(is);

      tlsContext.setServerDHParameters(publicKeyParameters);

      if (tlsContext.getProtocolVersion() == ProtocolVersion.DTLS12
          || tlsContext.getProtocolVersion() == ProtocolVersion.TLS12) {
        currentPointer = nextPointer;
        nextPointer++;
        HashAlgorithm ha = HashAlgorithm.getHashAlgorithm(message[currentPointer]);
        protocolMessage.setHashAlgorithm(ha.getValue());

        currentPointer = nextPointer;
        nextPointer++;
        SignatureAlgorithm sa = SignatureAlgorithm.getSignatureAlgorithm(message[currentPointer]);
        protocolMessage.setSignatureAlgorithm(sa.getValue());
      }
      currentPointer = nextPointer;
      nextPointer = currentPointer + HandshakeByteLength.SIGNATURE_LENGTH;
      int signatureLength =
          ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer));
      protocolMessage.setSignatureLength(signatureLength);

      currentPointer = nextPointer;
      nextPointer = currentPointer + signatureLength;
      protocolMessage.setSignature(Arrays.copyOfRange(message, currentPointer, nextPointer));

      protocolMessage.setCompleteResultingMessage(
          Arrays.copyOfRange(message, pointer, nextPointer));

      return nextPointer;
    } catch (IOException ex) {
      throw new WorkflowExecutionException("DH public key parsing failed", ex);
    }
  }
  @Override
  public byte[] prepareMessageAction() {
    // To use true DH ephemeral we need to precompute the prime number P(DH modulus)
    /**
     * int defaultPrimeProbability = 30;
     *
     * <p>DHParametersGenerator generator = new DHParametersGenerator(); //Genration of a higher bit
     * prime number takes too long (512 bits takes 2 seconds) generator.init(512,
     * defaultPrimeProbability, new SecureRandom()); DHParameters params =
     * generator.generateParameters();
     */
    DHPublicKeyParameters dhPublic;

    // fixed DH modulus P and DH generator G
    byte[] pArray =
        ArrayConverter.hexStringToByteArray(
            "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc"
                + "74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d"
                + "51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24"
                + "117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83"
                + "655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca1821"
                + "7c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695"
                + "5817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff");
    byte[] gArray = {0x02};
    BigInteger p = new BigInteger(1, pArray);
    BigInteger g = new BigInteger(1, gArray);
    DHParameters params = new DHParameters(p, g);

    KeyGenerationParameters kgp = new DHKeyGenerationParameters(new SecureRandom(), params);
    DHKeyPairGenerator keyGen = new DHKeyPairGenerator();
    keyGen.init(kgp);
    AsymmetricCipherKeyPair serverKeyPair = keyGen.generateKeyPair();

    dhPublic = (DHPublicKeyParameters) serverKeyPair.getPublic();
    DHPrivateKeyParameters dhPrivate = (DHPrivateKeyParameters) serverKeyPair.getPrivate();

    protocolMessage.setG(dhPublic.getParameters().getG());
    protocolMessage.setP(dhPublic.getParameters().getP());
    protocolMessage.setPublicKey(dhPublic.getY());
    protocolMessage.setPrivateKey(dhPrivate.getX());
    tlsContext.setServerDHPrivateKeyParameters(dhPrivate);

    byte[] serializedP = BigIntegers.asUnsignedByteArray(protocolMessage.getP().getValue());
    protocolMessage.setSerializedP(serializedP);
    protocolMessage.setSerializedPLength(serializedP.length);

    byte[] serializedG = BigIntegers.asUnsignedByteArray(protocolMessage.getG().getValue());
    protocolMessage.setSerializedG(serializedG);
    protocolMessage.setSerializedGLength(serializedG.length);

    byte[] serializedPublicKey =
        BigIntegers.asUnsignedByteArray(protocolMessage.getPublicKey().getValue());
    protocolMessage.setSerializedPublicKey(serializedPublicKey);
    protocolMessage.setSerializedPublicKeyLength(serializedPublicKey.length);

    byte[] dhParams =
        ArrayConverter.concatenate(
            ArrayConverter.intToBytes(
                protocolMessage.getSerializedPLength().getValue(),
                HandshakeByteLength.DH_PARAM_LENGTH),
            protocolMessage.getSerializedP().getValue(),
            ArrayConverter.intToBytes(
                protocolMessage.getSerializedGLength().getValue(),
                HandshakeByteLength.DH_PARAM_LENGTH),
            protocolMessage.getSerializedG().getValue(),
            ArrayConverter.intToBytes(
                protocolMessage.getSerializedPublicKeyLength().getValue(),
                HandshakeByteLength.DH_PARAM_LENGTH),
            protocolMessage.getSerializedPublicKey().getValue());
    InputStream is = new ByteArrayInputStream(dhParams);

    try {
      ServerDHParams publicKeyParameters = ServerDHParams.parse(is);

      tlsContext.setServerDHParameters(publicKeyParameters);

      KeyStore ks = tlsContext.getKeyStore();

      // could be extended to choose the algorithms depending on the certificate
      SignatureAndHashAlgorithm selectedSignatureHashAlgo =
          new SignatureAndHashAlgorithm(SignatureAlgorithm.RSA, HashAlgorithm.SHA1);
      protocolMessage.setSignatureAlgorithm(
          selectedSignatureHashAlgo.getSignatureAlgorithm().getValue());
      protocolMessage.setHashAlgorithm(selectedSignatureHashAlgo.getHashAlgorithm().getValue());

      Key key = ks.getKey(tlsContext.getAlias(), tlsContext.getPassword().toCharArray());

      RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;

      Signature instance = Signature.getInstance(selectedSignatureHashAlgo.getJavaName());
      instance.initSign(rsaKey);
      LOGGER.debug(
          "SignatureAndHashAlgorithm for ServerKeyExchange message: {}",
          selectedSignatureHashAlgo.getJavaName());

      byte[] toBeSignedBytes =
          ArrayConverter.concatenate(
              tlsContext.getClientRandom(), tlsContext.getServerRandom(), dhParams);

      instance.update(toBeSignedBytes);
      byte[] signature = instance.sign();
      protocolMessage.setSignature(signature);
      protocolMessage.setSignatureLength(signature.length);

      byte[] result =
          ArrayConverter.concatenate(
              dhParams,
              new byte[] {
                protocolMessage.getHashAlgorithm().getValue(),
                protocolMessage.getSignatureAlgorithm().getValue()
              },
              ArrayConverter.intToBytes(
                  protocolMessage.getSignatureLength().getValue(),
                  HandshakeByteLength.SIGNATURE_LENGTH),
              protocolMessage.getSignature().getValue());

      protocolMessage.setLength(result.length);

      long header =
          (HandshakeMessageType.SERVER_KEY_EXCHANGE.getValue() << 24)
              + protocolMessage.getLength().getValue();

      protocolMessage.setCompleteResultingMessage(
          ArrayConverter.concatenate(ArrayConverter.longToUint32Bytes(header), result));

    } catch (KeyStoreException
        | NoSuchAlgorithmException
        | UnrecoverableKeyException
        | InvalidKeyException
        | SignatureException
        | IOException ex) {
      throw new ConfigurationException(ex.getLocalizedMessage(), ex);
    }

    return protocolMessage.getCompleteResultingMessage().getValue();
  }