All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.whispersystems.curve25519.Curve25519 Maven / Gradle / Ivy

There is a newer version: 0.5.0
Show newest version
/**
 * Copyright (C) 2014-2016 Open Whisper Systems
 *
 * Licensed according to the LICENSE file in this repository.
 */

package org.whispersystems.curve25519;

/**
 * A Curve25519 interface for generating keys, calculating agreements, creating signatures,
 * and verifying signatures.
 *
 * @author Moxie Marlinspike
 */
public class Curve25519 {

  public static final String NATIVE = "native";
  public static final String JAVA   = "java";
  public static final String J2ME   = "j2me";
  public static final String BEST   = "best";

  public static Curve25519 getInstance(String type) throws NoSuchProviderException {
    return getInstance(type, null);
  }

  public static Curve25519 getInstance(String type, SecureRandomProvider random)
      throws NoSuchProviderException
  {
    if      (NATIVE.equals(type)) return new Curve25519(constructNativeProvider(random));
    else if (JAVA.equals(type))   return new Curve25519(constructJavaProvider(random));
    else if (J2ME.equals(type))   return new Curve25519(constructJ2meProvider(random));
    else if (BEST.equals(type))   return new Curve25519(constructOpportunisticProvider(random));
    else                          throw new NoSuchProviderException(type);
  }

  private final Curve25519Provider provider;

  private Curve25519(Curve25519Provider provider) {
    this.provider = provider;
  }

  /**
   * {@link Curve25519} is backed by either a native (via JNI)
   * or pure-Java provider.  By default it prefers the native provider, and falls back to the
   * pure-Java provider if the native library fails to load.
   *
   * @return true if backed by a native provider, false otherwise.
   */
  public boolean isNative() {
    return provider.isNative();
  }

  /**
   * Generates a Curve25519 keypair.
   *
   * @return A randomly generated Curve25519 keypair.
   */
  public Curve25519KeyPair generateKeyPair() {
    byte[] privateKey = provider.generatePrivateKey();
    byte[] publicKey  = provider.generatePublicKey(privateKey);

    return new Curve25519KeyPair(publicKey, privateKey);
  }

  /**
   * Calculates an ECDH agreement.
   *
   * @param publicKey The Curve25519 (typically remote party's) public key.
   * @param privateKey The Curve25519 (typically yours) private key.
   * @return A 32-byte shared secret.
   */
  public byte[] calculateAgreement(byte[] publicKey, byte[] privateKey) {
    if (publicKey == null || privateKey == null) {
      throw new IllegalArgumentException("Keys must not be null!");
    }

    if (publicKey.length != 32 || privateKey.length != 32) {
      throw new IllegalArgumentException("Keys must be 32 bytes!");
    }

    return provider.calculateAgreement(privateKey, publicKey);
  }

  /**
   * Calculates a Curve25519 signature.
   *
   * @param privateKey The private Curve25519 key to create the signature with.
   * @param message The message to sign.
   * @return A 64-byte signature.
   */
  public byte[] calculateSignature(byte[] privateKey, byte[] message) {
    if (privateKey == null || privateKey.length != 32) {
      throw new IllegalArgumentException("Invalid private key length!");
    }

    byte[] random = provider.getRandom(64);
    return provider.calculateSignature(random, privateKey, message);
  }

  /**
   * Verify a Curve25519 signature.
   *
   * @param publicKey The Curve25519 public key the signature belongs to.
   * @param message The message that was signed.
   * @param signature The signature to verify.
   * @return true if valid, false if not.
   */
  public boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature) {
    if (publicKey == null || publicKey.length != 32) {
      throw new IllegalArgumentException("Invalid public key!");
    }

    if (message == null || signature == null || signature.length != 64) {
      return false;
    }

    return provider.verifySignature(publicKey, message, signature);
  }

  /**
   * Calculates a Unique Curve25519 signature.
   *
   * @param privateKey The private Curve25519 key to create the signature with.
   * @param message The message to sign.
   * @return A 96-byte signature.
   */
  public byte[] calculateVrfSignature(byte[] privateKey, byte[] message) {
    if (privateKey == null || privateKey.length != 32) {
      throw new IllegalArgumentException("Invalid private key!");
    }

    byte[] random = provider.getRandom(64);
    return provider.calculateVrfSignature(random, privateKey, message);
  }

  /**
   * Verify a Unique Curve25519 signature.
   *
   * @param publicKey The Curve25519 public key the unique signature belongs to.
   * @param message The message that was signed.
   * @param signature The unique signature to verify.
   *
   * @return The vrf for this signature.
   */
  public byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
      throws VrfSignatureVerificationFailedException
  {
    if (publicKey == null || publicKey.length != 32) {
      throw new IllegalArgumentException("Invalid public key!");
    }

    if (message == null || signature == null || signature.length != 96) {
      throw new VrfSignatureVerificationFailedException("Invalid message or signature format");
    }

    return provider.verifyVrfSignature(publicKey, message, signature);
  }

  private static Curve25519Provider constructNativeProvider(SecureRandomProvider random) throws NoSuchProviderException {
    return constructClass("NativeCurve25519Provider", random);
  }

  private static Curve25519Provider constructJavaProvider(SecureRandomProvider random) throws NoSuchProviderException {
    return constructClass("JavaCurve25519Provider", random);
  }

  private static Curve25519Provider constructJ2meProvider(SecureRandomProvider random) throws NoSuchProviderException {
    return constructClass("J2meCurve25519Provider", random);
  }

  private static Curve25519Provider constructOpportunisticProvider(SecureRandomProvider random) throws NoSuchProviderException {
    return constructClass("OpportunisticCurve25519Provider", random);
  }

  private static Curve25519Provider constructClass(String name, SecureRandomProvider random) throws NoSuchProviderException {
    try {
      Curve25519Provider provider =  (Curve25519Provider)Class.forName("org.whispersystems.curve25519." + name).newInstance();

      if (random != null) {
        provider.setRandomProvider(random);
      }

      return provider;
    } catch (InstantiationException e) {
      throw new NoSuchProviderException(e);
    } catch (IllegalAccessException e) {
      throw new NoSuchProviderException(e);
    } catch (ClassNotFoundException e) {
      throw new NoSuchProviderException(e);
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy