using System; using System.Linq; using System.Numerics; namespace S22.Sasl.Mechanisms.Srp { /// /// Represents a "multi-precision integer" (MPI) as is described in the /// SRP specification (3.2 Multi-Precision Integers, p.5). /// /// Multi-Precision Integers, or MPIs, are positive integers used /// to hold large integers used in cryptographic computations. internal class Mpi { /// /// The underlying BigInteger instance used to represent this /// "multi-precision integer". /// public BigInteger Value { get; set; } /// /// Creates a new "multi-precision integer" from the specified array /// of bytes. /// /// A big-endian sequence of bytes forming the /// integer value of the multi-precision integer. public Mpi(byte[] data) { byte[] b = new byte[data.Length]; Array.Copy(data.Reverse().ToArray(), b, data.Length); ByteBuilder builder = new ByteBuilder().Append(b); // We append a null byte to the buffer which ensures the most // significant bit will never be set and the big integer value // always be positive. if (b.Last() != 0) builder.Append(0); Value = new BigInteger(builder.ToArray()); } /// /// Creates a new "multi-precision integer" from the specified BigInteger /// instance. /// /// The BigInteger instance to initialize the MPI /// with. public Mpi(BigInteger value) : this(value.ToByteArray().Reverse().ToArray()) { } /// /// Returns a sequence of bytes in big-endian order forming the integer /// value of this "multi-precision integer" instance. /// /// Returns a sequence of bytes in big-endian order representing /// this "multi-precision integer" instance. public byte[] ToBytes() { byte[] b = Value.ToByteArray().Reverse().ToArray(); // Strip off the 0 byte. if (b[0] == 0) return b.Skip(1).ToArray(); return b; } /// /// Serializes the "multi-precision integer" into a sequence of bytes /// according to the requirements of the SRP specification. /// /// A big-endian sequence of bytes representing the integer /// value of the MPI. public byte[] Serialize() { // MPI's expect a big-endian sequence of bytes forming the integer // value, whereas BigInteger uses little-endian. byte[] data = ToBytes(); ushort length = Convert.ToUInt16(data.Length); return new ByteBuilder() .Append(length, true) .Append(data) .ToArray(); } } }