public byte[] PerformKeyAgreement (byte[] otherPublicKey1, byte[] otherPublicKey2, int keyDataLength) { ECPoint otherQ1 = new ECPoint (_params.Domain.Group, otherPublicKey1); ECPoint otherQ2 = new ECPoint (_params.Domain.Group, otherPublicKey2); IFiniteField ff = _params.Domain.FieldN; // MQV Primitives if (_params.KeyPair1.D == null) _params.KeyPair1.CreateNewPrivateKey (); if (_params.KeyPair2.D == null) _params.KeyPair2.CreateNewPrivateKey (); if (_params.KeyPair2.Q == null) _params.KeyPair2.CreatePublicKeyFromPrivateKey (); int logBits = _params.Domain.N.BitCount (); logBits = (logBits >> 1) + ((logBits & 1) == 0 ? 0 : 1); Number mod = Number.One << logBits; Number mask = mod - Number.One; Number q2u = (_params.KeyPair2.Q.Export ().X & mask) + mod; Number s = ff.Add (_params.KeyPair2.D, ff.Multiply (q2u, _params.KeyPair1.D)); Number q2v = (otherQ2.Export ().X & mask) + mod; ECPoint P = otherQ2.Add (otherQ1.Multiply (q2v)).Multiply (s * new Number (new uint[] {_params.Domain.H})); if (P.IsInifinity ()) throw new CryptographicException (); int keyBytes = (int)((_params.Domain.Bits >> 3) + ((_params.Domain.Bits & 7) == 0 ? 0 : 1)); byte[] sharedSecretValue = P.Export ().X.ToByteArray (keyBytes, false); // KDF _kdf.SharedInfo = _sharedInfo; return _kdf.Calculate (sharedSecretValue, keyDataLength); }
byte[] PerformKeyAgreement (ECPoint other, int keyDataLength) { // Diffie-Hellman Primitives if (_params.D == null) _params.CreateNewPrivateKey (); Number sharedSecretField = other.Multiply (_params.D).Export ().X; byte[] sharedSecretValue = new byte[(_params.Domain.Bits >> 3) + ((_params.Domain.Bits & 7) == 0 ? 0 : 1)]; sharedSecretField.CopyToBigEndian (sharedSecretValue, 0, sharedSecretValue.Length); // KDF if (_kdf == null) return sharedSecretValue; _kdf.SharedInfo = _sharedInfo; return _kdf.Calculate (sharedSecretValue, keyDataLength); }
public byte[] Decrypt (byte[] value) { if (_params.Q == null) { if (_params.D == null) throw new CryptographicException (); _params.CreatePublicKeyFromPrivateKey (); } int domainLen = (int)((_domain.Bits >> 3) + ((_domain.Bits & 7) == 0 ? 0 : 1)); int macKeyLen = _mac.HashSize >> 3; // Step.1 if (value[0] != 2 && value[0] != 3 && value[0] != 4) throw new CryptographicException (); byte[] RBytes = new byte[domainLen + 1]; byte[] EM = new byte[value.Length - RBytes.Length - macKeyLen]; byte[] D = new byte[macKeyLen]; if (value.Length != RBytes.Length + EM.Length + D.Length) throw new CryptographicException (); Array.Copy (value, 0, RBytes, 0, RBytes.Length); Array.Copy (value, RBytes.Length, EM, 0, EM.Length); Array.Copy (value, RBytes.Length + EM.Length, D, 0, D.Length); int encKeyLen = (_symmetricAlgo == null ? EM.Length : _symmetricAlgo.KeySize >> 3);; // Step.2 ECPoint R = new ECPoint (_domain.Group, RBytes); // Step.3 // TODO: Step.3 // Step.4 & 5 // TODO: Cofactor Diffie-Hellmanプリミティブを利用するオプションを追加する byte[] Z = R.Multiply (_params.D).Export ().X.ToByteArray (domainLen, false); // Step.6 byte[] K = _kdf.Calculate (Z, encKeyLen + macKeyLen); // Step.7 byte[] EK = null; if (_symmetricAlgo != null) { EK = new byte[encKeyLen]; for (int i = 0; i < EK.Length; i ++) EK[i] = K[i]; } byte[] MK = new byte[macKeyLen]; for (int i = 0; i < MK.Length; i++) MK[i] = K[K.Length - MK.Length + i]; // Step.8 // TODO: HMAC-SHA1-80への対応 _mac.Key = MK; _mac.Initialize (); _mac.TransformBlock (EM, 0, EM.Length, null, 0); if (_sharedInfo == null) _mac.TransformFinalBlock (EM, 0, 0); else _mac.TransformFinalBlock (_sharedInfo, 0, _sharedInfo.Length); byte[] hash = _mac.Hash; for (int i = 0; i < hash.Length; i ++) if (hash[i] != D[i]) throw new CryptographicException (); // Step.9 byte[] result = new byte[EM.Length]; if (_symmetricAlgo == null) { for (int i = 0; i < result.Length; i ++) result[i] = (byte)(EM[i] ^ K[i]); } else { int blockBytes = _symmetricAlgo.BlockSize >> 3; using (ICryptoTransform transform = _symmetricAlgo.CreateDecryptor (EK, new byte[blockBytes])) { int i = 0; for (; i < result.Length - blockBytes; i += blockBytes) transform.TransformBlock (EM, i, blockBytes, result, i); byte[] temp = transform.TransformFinalBlock (EM, i, EM.Length - i); Buffer.BlockCopy (temp, 0, result, i, temp.Length); if (temp.Length != blockBytes) Array.Resize<byte> (ref result, i + temp.Length); } } return result; }