// maps single character of plain text to eliptic curve point is not optimal // - its slow and ciphertext is large :( needs remake // - Koblitz’s Method for Encoding Plaintext // - http://informatika.stei.itb.ac.id/~rinaldi.munir/Kriptografi/2014-2015/IJCSE10-02-05-08.pdf #region ENCRYPTION - char mapping ///// <summary> ///// Encrypts chars of plain text to cipher text. ///// one char message is represented by 2 eliptic curve points ///// in comprimed form after encryption. ///// </summary> ///// <param name="plainText">the plain text</param> ///// <param name="publicKey">the public key</param> ///// <returns>cipherText</returns> //public string Encrypt(string plainText, string publicKey) //{ // string cipher = ""; // ElipticCurvePoint Q = serialiser.FromHex(publicKey); // foreach (char c in plainText) // { // BigInteger k = rnd.Next(1, curve.N - 1); // ElipticCurvePoint C1 = calculator.Multiply(k, curve.G); // ElipticCurvePoint C2 = calculator.Add(CharToPoint(c), calculator.Multiply(k, Q)); // cipher += serialiser.ToHex(C1) + serialiser.ToHex(C2); // } // return cipher; //} ///// <summary> ///// Decrypts cipherText in plainText ///// </summary> ///// <param name="cipher">cipher text</param> ///// <param name="privateKey">private key</param> ///// <returns>original plain text</returns> //public string Decrypt(string cipher, string privateKey) //{ // BigInteger pk = BigInteger.Parse(privateKey, NumberStyles.HexNumber); // string message = ""; // foreach (string c in Split(cipher, curve.BitSize / 2 + 4)) // { // string c1 = c.Substring(0, c.Length / 2); // string c2 = c.Substring(c.Length / 2); // ElipticCurvePoint C1 = serialiser.FromHex(c1); // ElipticCurvePoint C2 = serialiser.FromHex(c2); // message += PointTochar(calculator.Add(C2, calculator.Inverse(calculator.Multiply(pk, C1)))); // } // return message; //} ///// <summary> ///// maps single utf-16 code unit to eliptic curve point. ///// see - standard probabilistic encoding ///// </summary> ///// <param name="m">the character to be mapped</param> ///// <returns>eliptic curve point</returns> //private ElipticCurvePoint CharToPoint(char m) //{ // BigInteger k = curve.P / int.MaxValue; // BigInteger mkplus = k.ModMul(m, curve.P); // while (true) // { // mkplus = mkplus.ModAdd(1, curve.P); // ElipticCurvePoint mappedPoint = calculator.FindPointByX(mkplus); // if (mappedPoint != null) // return mappedPoint; // } //} ///// <summary> ///// Gets char from eliptic curve point ///// see - standard probabilistic encoding ///// - Koblitz’s Method for Encoding Plaintext ///// - http://informatika.stei.itb.ac.id/~rinaldi.munir/Kriptografi/2014-2015/IJCSE10-02-05-08.pdf ///// </summary> ///// <param name="point">eliptic curve point</param> ///// <returns>character</returns> //private char PointTochar(ElipticCurvePoint point) //{ // BigInteger k = curve.P / int.MaxValue; // return (char)((point.X - 1) / k); //} #endregion // maps block of text into eliptic curve point // faster safier and more optimal for cipher text size and speed // - Proposed Message Mapping Scheme // - http://onlinelibrary.wiley.com/doi/10.1002/sec.1702/full #region ENCRYPTION - textblocks mappig /// <summary> /// Encrypts chars of plain text to cipher text. /// one block of message text is represented by 2 eliptic curve points /// in comprimed form after encryption. /// </summary> /// <param name="plainText">the plain text</param> /// <param name="publicKey">the public key</param> /// <returns>cipherText</returns> public byte[] Encrypt(string plainText, byte[] publicKey, Encoding enc, bool comprimed = false) { List <ElipticCurvePoint> result = new List <ElipticCurvePoint>(); int encByteSize = enc.GetBytes("a").Length; int M = ((curve.BitSize / 8) - 1) / encByteSize * encByteSize; int N = curve.BitSize / 8 - M; byte[] plainTextBytes = enc.GetBytes(plainText); ElipticCurvePoint Q = serialiser.DeserialisePoint(publicKey); for (int i = 0; i *M <= plainTextBytes.Length; i++) { byte[] buffer = new byte[M + N]; Buffer.BlockCopy(plainTextBytes, i * M, buffer, N, Math.Min(M, plainTextBytes.Length - i * M)); BigInteger x = new BigInteger(buffer); ElipticCurvePoint point = calculator.FindPointByX(x); while (point == null) { point = calculator.FindPointByX(x++); } BigInteger k = rnd.Next(1, curve.N - 1); ElipticCurvePoint C1 = calculator.Multiply(k, curve.G); ElipticCurvePoint C2 = calculator.Add(point, calculator.Multiply(k, Q)); result.Add(C1); result.Add(C2); } return(serialiser.SerialisePoints(result, comprimed)); }
/// <summary> /// gets inverse point to specific point. /// </summary> /// <param name="point">eliptic curve point</param> /// <returns>inverse point</returns> public ElipticCurvePoint Inverse(ElipticCurvePoint point) { if (point == null) { throw new ArgumentException("cannot find an inverse of zero point.. "); } return(new ElipticCurvePoint(point.X, point.Y.ModNeg(curve.P))); }
/// <summary> /// checks if eliptic curve point lies on curve /// </summary> /// <param name="p"></param> /// <returns> /// true - point lies on curve /// false - point doesnt lie on curve /// </returns> internal bool IsCurvePoint(ElipticCurvePoint p) { if (p == null) { return(true); } //return p.Y.ModPow(2, curve.P).ModEquals(p.X.ModPow(3, curve.P).ModAdd(p.X.ModMul(curve.A, curve.P), curve.P).ModAdd(curve.B, curve.P), curve.P); return(BigInteger.ModPow(p.Y, 2, curve.P) == (BigInteger.ModPow(p.X, 3, curve.P) + p.X * curve.A + curve.B).Mod(curve.P)); }
/// <summary> /// set parameters of eliptic curve /// </summary> /// <param name="p"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="g"></param> /// <param name="n"></param> /// <param name="h"></param> /// <param name="bitSize"></param> private ElipticCurve(BigInteger p, BigInteger a, BigInteger b, ElipticCurvePoint g, BigInteger n, BigInteger h, int bitSize, string name) { P = p; A = a; B = b; G = g; N = n; //skontroluj bod 3 v diplomovke aj s G H = h; BitSize = bitSize; Name = name; }
public byte[] SharedSecret(byte[] privateKey, byte[] publicKey) { BigInteger privateK = new BigInteger(privateKey); ElipticCurvePoint publicK = serialiser.DeserialisePoint(publicKey); ElipticCurvePoint P = calculator.Multiply(privateK, publicK); if (P == null) { return(null); } else { return(P.X.ToByteArray()); } }
/// <summary> /// Creates one eliptic curve point using x coordinate. /// If there is no point with x coordinate null is returned. /// </summary> /// <param name="x">the x coordinate of point</param> /// <returns>Found point or null.</returns> public ElipticCurvePoint FindPointByX(BigInteger x) { //BigInteger ySquare = x.ModPow(3, curve.P).ModAdd(x.ModMul(curve.A, curve.P), curve.P).ModAdd(curve.B, curve.P); BigInteger ySquare = (BigInteger.ModPow(x, 3, curve.P) + curve.A * x + curve.B).Mod(curve.P); //BigInteger yRoot = ySquare.ModPow((curve.P + 1) / 4, curve.P); BigInteger yRoot = BigInteger.ModPow(ySquare, (curve.P + 1) / 4, curve.P); ElipticCurvePoint result = new ElipticCurvePoint(x, yRoot); if (IsCurvePoint(result)) { return(result); } else { return(null); } }
/// <summary> /// multiplies eliptic curve point X times. Optimised algorhytm. /// </summary> /// <param name="times">multiplier</param> /// <param name="point">liptic curve point</param> /// <returns>multiplied eliptic curve point</returns> internal ElipticCurvePoint Multiply(BigInteger times, ElipticCurvePoint point) { if (times == 0) { return(null); } if (times == 1) { return(point); } ElipticCurvePoint splited = Multiply(times / 2, point); ElipticCurvePoint added = Add(splited, splited); if (!times.IsEven) { added = Add(added, point); } return(added); }
/// <summary> /// adds 2 eliptic curve point /// </summary> /// <param name="p">point 1</param> /// <param name="q">point 2</param> /// <returns>eliptic curve point or null if identitt element O</returns> public ElipticCurvePoint Add(ElipticCurvePoint p, ElipticCurvePoint q) { if (p == null) { return(q); } if (q == null) { return(p); } if (AreInverse(p, q)) { return(null); } BigInteger xr; BigInteger yr; BigInteger s; if (p.Equals(q)) { //s = p.X.ModPow(2, curve.P).ModMul(3, curve.P).ModAdd(curve.A, curve.P).ModDiv(p.Y.ModMul(2, curve.P), curve.P); s = (BigInteger.ModPow(p.X, 2, curve.P) * 3 + curve.A).ModDiv(p.Y * 2, curve.P); //xr = s.ModPow(2, curve.P).ModSub(p.X, curve.P).ModSub(p.X, curve.P); xr = (BigInteger.ModPow(s, 2, curve.P) - p.X - p.X).Mod(curve.P); //yr = s.ModMul(p.X.ModSub(xr, curve.P), curve.P).ModSub(p.Y, curve.P); yr = (s * (p.X - xr) - p.Y).Mod(curve.P); } else { s = (q.Y.ModSub(p.Y, curve.P)).ModDiv(q.X.ModSub(p.X, curve.P), curve.P); //s = (q.Y - p.Y).ModDiv((q.X - p.X), curve.P); not working //xr = s.ModPow(2, curve.P).ModSub(p.X, curve.P).ModSub(q.X, curve.P); xr = (BigInteger.ModPow(s, 2, curve.P) - p.X - q.X).Mod(curve.P); //yr = s.ModMul(p.X.ModSub(xr, curve.P), curve.P).ModSub(p.Y, curve.P); yr = (s * (p.X - xr) - p.Y).Mod(curve.P); } return(new ElipticCurvePoint(xr, yr)); }
/// <summary> /// serialises ec point into byte array over specified eliptic curve. /// first byte value meaning: /// 0x00 - zero point /// 0x04 - uncomprimed /// 0x02 - comprimed with even Y /// 0x03 - comprimed with odd Y /// </summary> /// <param name="point">point to serialise</param> /// <param name="comprimend">serialised point</param> /// <returns></returns> public byte[] SerialisePoint(ElipticCurvePoint point, bool comprimend) { int size = curve.P.ToByteArray().Length; if (comprimend) { byte[] result = new byte[1 + size]; if (point == null) { return(result); } byte[] xBytes = point.X.ToByteArray(); if (point.Y.IsEven) { result[0] = 0x02; } else { result[0] = 0x03; } Buffer.BlockCopy(xBytes, 0, result, 1, xBytes.Length); return(result); } else { byte[] result = new byte[1 + size * 2]; if (point == null) { return(result); } byte[] xBytes = point.X.ToByteArray(); byte[] yBytes = point.Y.ToByteArray(); result[0] = 0x04; Buffer.BlockCopy(xBytes, 0, result, 1, xBytes.Length); Buffer.BlockCopy(yBytes, 0, result, 1 + size, yBytes.Length); return(result); } }
/// <summary> /// Decrypts cipherText in plainText /// </summary> /// <param name="cipher">cipher text</param> /// <param name="privateKey">private key</param> /// <returns>original plain text</returns> public string Decrypt(byte[] cipher, byte[] privateKey, Encoding enc, bool comprimed = false) { BigInteger pk = new BigInteger(privateKey); int encByteSize = enc.GetBytes("a").Length; int M = ((curve.BitSize / 8) - 1) / encByteSize * encByteSize; int N = curve.BitSize / 8 - M; List <byte> xByte = new List <byte>(); ElipticCurvePoint[] points = serialiser.DeserielisePoints(cipher, comprimed).ToArray(); for (int i = 0; i < points.Count(); i += 2) { ElipticCurvePoint C1 = points[i]; ElipticCurvePoint C2 = points[i + 1]; ElipticCurvePoint m = calculator.Add(C2, calculator.Inverse(calculator.Multiply(pk, C1))); xByte.AddRange(m.X.ToByteArray().Skip(N)); while (xByte.Count % encByteSize != 0) { xByte.Add(0); } } return(enc.GetString(xByte.ToArray())); }
/// <summary> /// Creates signature to specified file using private key /// </summary> /// <param name="file">File to sign</param> /// <param name="privateKey">private key</param> /// <returns></returns> public byte[] Signature(string message, byte[] privateKey) { BigInteger hash = new BigInteger(HashMessage(message)); BigInteger r, s; BigInteger pk = new BigInteger(privateKey); do { BigInteger k = rnd.Next(1, curve.N - 1); ElipticCurvePoint x1y1 = calculator.Multiply(k, curve.G); r = x1y1.X.Mod(curve.N); //s = ((BigInteger)k.ModInv(curve.N)).ModMul(hash.ModAdd(privateKey.ModMul(r, curve.N), curve.N), curve.N); s = (((BigInteger)k.ModInv(curve.N)) * (hash + pk * r)).Mod(curve.N); } while (r == 0 || s == 0); int size = curve.N.ToByteArray().Length; byte[] result = new byte[size * 2]; byte[] rBytes = r.ToByteArray(); byte[] sBytes = s.ToByteArray(); Buffer.BlockCopy(rBytes, 0, result, 0, rBytes.Length); Buffer.BlockCopy(sBytes, 0, result, size, sBytes.Length); return(result); }
/// <summary> /// Deserialise ec point over specified eliptic curve /// </summary> /// <param name="bytes">serialised point</param> /// <returns>deserialised point</returns> internal ElipticCurvePoint DeserialisePoint(byte[] bytes) { //this is error if (bytes == null) { throw new InvalidPointFormatException("Cannot convert null to eliptic curve point. Zero point (null) is serialised with prefix 0x00", bytes); } if (bytes.Length == 0) { throw new InvalidPointFormatException("Cannot convert empty byte array to eliptic curve point. Zero point (null) is serialised with prefix 0x00", bytes); } int size = curve.P.ToByteArray().Length; //deserialise zero point if (bytes[0] == 0x00) { return(null); } //deserielse uncomprimed point if (bytes[0] == 0x04) { if (bytes.Length != size * 2 + 1) { throw new InvalidPointFormatException($"point serialised over curve {curve.Name} should have {size * 2 + 1} bytes in uncomprimed form.", bytes); } byte[] xBytes = new byte[size]; byte[] yBytes = new byte[size]; Buffer.BlockCopy(bytes, 1, xBytes, 0, size); Buffer.BlockCopy(bytes, 1 + size, yBytes, 0, size); ElipticCurvePoint point = new ElipticCurvePoint(new BigInteger(xBytes), new BigInteger(yBytes)); if (!calc.IsCurvePoint(point)) { throw new InvalidPointFormatException("deserialised point was not found on curve...", bytes); } return(point); } //deserialise comprimed point else { if (bytes.Length != size + 1) { throw new InvalidPointFormatException($"point serialised over curve {curve.Name} should have {size + 1} bytes in comprimed form.", bytes); } bool yEven; switch (bytes[0]) { case 0x02: yEven = true; break; case 0x03: yEven = false; break; default: throw new InvalidPointFormatException("First byte of serialised point should be 0x00 for zero point, 0x04 for uncomprimed, 0x02 for comprimed with even Y and 0x03 for comprimed with odd Y.", bytes); } byte[] xBytes = new byte[size]; Buffer.BlockCopy(bytes, 1, xBytes, 0, size); BigInteger x = new BigInteger(xBytes); ElipticCurvePoint point = calc.FindPointByX(x); if (point == null) { throw new InvalidPointFormatException("deserialised point was not found on curve...", bytes); } if (point.Y.IsEven == yEven) { return(point); } else { return(calc.Inverse(point)); } } }
/// <summary> /// Verifies signature to specified file using public key /// </summary> /// <param name="file">signed file</param> /// <param name="signature">signature</param> /// <param name="publicKey">public key</param> /// <returns></returns> public bool VerifySignature(string message, byte[] signature, byte[] publicKey) { int size = curve.N.ToByteArray().Length; byte[] rBytes = new byte[size]; byte[] sBytes = new byte[size]; Buffer.BlockCopy(signature, 0, rBytes, 0, size); Buffer.BlockCopy(signature, size, sBytes, 0, size); BigInteger r = new BigInteger(rBytes); BigInteger s = new BigInteger(sBytes); //1. public key point isnt identity element O' and coordinates are valid //2. public key point lies on curve (exception is thrown if not) ElipticCurvePoint publicKeyPoint = serialiser.DeserialisePoint(publicKey); if (publicKeyPoint == null) { return(false); } //3. N x publicKey == O ElipticCurvePoint zero = calculator.Multiply(curve.N, publicKeyPoint); if (zero != null) { return(false); } //1. r and s in [1, N-1] if (r == 0 || r > curve.N - 1) { return(false); } if (s == 0 || s > curve.N - 1) { return(false); } //2. calculate hash of message BigInteger hash = new BigInteger(HashMessage(message)); //3. w = 1/s mod N BigInteger w = (BigInteger)s.ModInv(curve.N); //4. u1 = hash * w mod N // u2 = r * w mod N BigInteger u1 = w.ModMul(hash, curve.N); BigInteger u2 = w.ModMul(r, curve.N); //5. P(x1,y1) = u1 * G + u2 * publicKey mod N // if P(x1,y1) == O => FALSE ElipticCurvePoint x1y1 = calculator.Add(calculator.Multiply(u1, curve.G), calculator.Multiply(u2, publicKeyPoint)); if (x1y1 == null) { return(false); } //6. r == x1 mod n => TRUE => ELSE FALSE if (r.ModEquals(x1y1.X, curve.N)) { return(true); } else { return(false); } }
/// <summary> /// Checks if 2 points are inverse /// </summary> /// <param name="point1">point 1</param> /// <param name="point2">point 2</param> /// <returns></returns> internal bool AreInverse(ElipticCurvePoint point1, ElipticCurvePoint point2) { return(point1.X == point2.X && (point1.Y + point2.Y).Mod(curve.P) == 0); }
/// <summary> /// compares 2 points /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { ElipticCurvePoint point = (ElipticCurvePoint)obj; return(point.X == X && point.Y == Y); }