📄 elgamalalgorithm.java
字号:
// $Id: ElGamalAlgorithm.java,v 1.2 1997/12/10 06:39:51 raif Exp $//// $Log: ElGamalAlgorithm.java,v $// Revision 1.2 1997/12/10 06:39:51 raif// *** empty log message ***//// 1997.12.10 --RSN:// + made it public final and its methods public.//// Revision 1.1 1997/12/07 06:37:26 hopwood// + Major overhaul of ElGamal to match RSA.//// Revision 0.1.0 1997/11/22 David Hopwood// + Original version.//// $Endlog$/* * Copyright (c) 1997 Systemics Ltd * on behalf of the Cryptix Development Team. All rights reserved. */package cryptix.provider.elgamal;import cryptix.CryptixException;import cryptix.util.core.Debug;import java.io.PrintWriter;import java.math.BigInteger;import java.util.Random;/** * A class that calculates the ElGamal family of algorithms (encryption, * decryption, signing and verification). * <p> * <b>References:</b> * <ol> * <li> Bruce Schneier, * "Section 19.6 ElGamal," * <cite>Applied Cryptography, 2nd edition</cite>, * John Wiley & Sons, 1996. * </ol> * <p> * <b>Copyright</b> © 1997 * <a href="http://www.systemics.com/">Systemics Ltd</a> on behalf of the * <a href="http://www.systemics.com/docs/cryptix/">Cryptix Development Team</a>. * <br>All rights reserved. * <p> * <b>$Revision: 1.2 $</b> * @author David Hopwood * @since Cryptix 2.2.2 */public final class ElGamalAlgorithm{ private ElGamalAlgorithm() {} // static methods only// Debugging methods and vars.//........................................................................... private static final boolean DEBUG = Debug.GLOBAL_DEBUG; private static final int debuglevel = DEBUG ? Debug.getLevel("ElGamal", "ElGamalAlgorithm") : 0; private static final PrintWriter err = DEBUG ? Debug.getOutput() : null; private static void debug(String s) { err.println("ElGamalAlgorithm: " + s); }// Constants//........................................................................... private static final BigInteger ZERO = BigInteger.valueOf(0L); private static final BigInteger ONE = BigInteger.valueOf(1L);// Own methods//........................................................................... /** * The encryption algorithm for ElGamal. The two parts of the ciphertext, * <i>a</i> and <i>b</i>, will be stored in <code>ab[0]</code> and * <code>ab[1]</code> respectively. * * @param M the plaintext. * @param ab a 2-element BigInteger array in which to store the ciphertext. * @param p the prime from the public key. * @param g the generator from the public key. * @param y the value of <i>y</i> from the public key. * @param rng a random number generator to be used for encryption. */ public static void encrypt(BigInteger M, BigInteger[] ab, BigInteger p, BigInteger g, BigInteger y, Random rng) { BigInteger p_minus_1 = p.subtract(ONE); // choose a random k, relatively prime to p-1. BigInteger k; do { // values of k with the same number of bits as p won't be chosen, but // that shouldn't be a problem. k = new BigInteger(p.bitLength()-1, rng); if (!(k.testBit(0))) k = k.setBit(0); // make sure k is odd } while (!(k.gcd(p_minus_1).equals(ONE))); ab[0] /* a */ = g.modPow(k, p); ab[1] /* b */ = y.modPow(k, p).multiply(M).mod(p); } /** * The decryption algorithm for ElGamal. <i>a</i> and <i>b</i> are the * two parts of the ciphertext (using the same convention as given in * Schneier). * * @param a the first part of the ciphertext. * @param b the second part of the ciphertext. * @param p the prime from the private key. * @param g the generator from the private key. * @param x the value of <i>x</i> from the private key. * @return the plaintext. */ public static BigInteger decrypt(BigInteger a, BigInteger b, BigInteger p, BigInteger g, BigInteger x) { try { return b.multiply(a.modPow(x, p).modInverse(p)).mod(p); } catch (ArithmeticException e) { // Shouldn't happen, but might if the key was not generated properly, // or if initEncrypt or initDecrypt is called at the same time by // another thread. // SECURITY: can't include values of a, x and p in the detail message, // because x is secret, and a or p may be secret depending on the // application. throw new CryptixException("ElGamal: " + e.getClass().getName() + " while calculating a.modPow(x, p).modInverse(p) - maybe key was" + " not generated properly?"); } } /** * The signature algorithm for ElGamal. <i>ab</i> should be a two-element * BigInteger array. The two parts of the signature, <i>a</i> and <i>b</i>, * will be stored in <code>ab[0]</code> and <code>ab[1]</code> respectively. * * @param M the value to be signed. * @param ab an array in which to store the result. * @param p the prime from the private key. * @param g the generator from the private key. * @param x the value of <i>x</i> from the private key. * @param rng a random number generator to be used for signing. * @return true iff the signature is valid. */ public static void sign(BigInteger M, BigInteger[] ab, BigInteger p, BigInteger g, BigInteger x, Random rng) { BigInteger p_minus_1 = p.subtract(ONE); // choose a random k, relatively prime to p-1. BigInteger k; do { // values of k with the same number of bits as p won't be chosen, but // that shouldn't be a problem. k = new BigInteger(p.bitLength()-1, rng); if (!(k.testBit(0))) k = k.setBit(0); // make sure k is odd } while (!(k.gcd(p_minus_1).equals(ONE))); BigInteger a = g.modPow(k, p); ab[0] = a; // solve for b in the equation: // M = (x.a + k.b) mod (p-1) // i.e. // b = (inverse of k mod p-1).(M - x.a) mod (p-1) try { ab[1] /* b */ = k.modInverse(p_minus_1) .multiply(M.subtract(x.multiply(a)).mod(p_minus_1)) .mod(p_minus_1); } catch (ArithmeticException e) { // Shouldn't happen (because modInverse is the only method that // throws ArithmeticException, k is relatively prime to p-1, and // p-1 > 0). // // SECURITY: can't include values of k and p-1 in the detail message, // because k is secret, and p may be secret depending on the application. throw new CryptixException( "ElGamal: ArithmeticException while calculating k.modInverse(p-1)"); } } /** * The verification algorithm for ElGamal. Returns true iff the signature was * verified successfully. * * @param M the value that was signed. * @param a the first part of the signature. * @param b the second part of the signature. * @param p the prime from the public key. * @param g the generator from the public key. * @param y the value of <i>y</i> from the public key. * @return true iff the signature is valid. */ public static boolean verify(BigInteger M, BigInteger a, BigInteger b, BigInteger p, BigInteger g, BigInteger y) { BigInteger p_minus_1 = p.subtract(ONE); // sanity checks if (M.compareTo(ZERO) < 0 || M.compareTo(p_minus_1) >= 0 || a.compareTo(ZERO) < 0 || a.compareTo(p_minus_1) >= 0 || b.compareTo(ZERO) < 0 || b.compareTo(p_minus_1) >= 0) return false; // accept iff y^a.a^b = g^M (mod p) return y.modPow(a, p).multiply(a.modPow(b, p)).mod(p) .equals(g.modPow(M, p)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -