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();
}
}
}