1. Devin Martin
  2. OTP-Sharp

Wiki

Clone wiki

OTP-Sharp / Key Providers

OtpSharp has an extensible key provider model. It comes packaged with only one key type (InMemoryKey) but others can be created and used. This is done by creating an implementation of the IKeyProvider interface which represents (but doesn't necessarily contain) a key. The only interaction that OtpSharp needs with a key is the ability to compute an HMAC against the key. That is the only method that the abstract type requires.

This allows OtpSharp to use keys stored in HSMs or other hardened cryptographic key stores without compromising the security of the key, while still leveraging OtpSharp to do the formatting of one-time-passwords.

Example

This example is going to assume that you have a fictitious HSM with a master key stored inside. The HSM has a custom module on it that has the ability to derive a key from the master (via hashing it with a a serial number or some such secure algorithm) and compute HMACs against the derived key. This is a perfect scenario for (H|T)OTP and would likely require a custom module to be created and installed for your particular HSM. Obviously that isn't in the scope of this example as each HSM has different capabilities.

We are going to assume that an API for the HSM would look something like this. This is an oversimplification but again, the implementation details of an HSM provider aren't part of this at all.

public interface IOtpHsm
{
    byte[] ComputeSha256HmacAgainstDerivedKey(long derivedKeySerialNumber, byte[] data);
}

The HSM takes a serial number, creates a derived key from the master based on that serial number, then computes an HMAC using that derived key and the provided data.

A key implementation for OtpSharp that uses this HSM provider would look something like this.

public class HsmKey : IKeyProvider 
{
    private readonly long derivedKeySerialNumber;
    private readonly IOtpHsm otpHsm;
    public HsmKey(long derivedKeySerialNumber, IOtpHsm otpHsm)
    {
        this.derivedKeySerialNumber = derivedKeySerialNumber;
        this.otpHsm = otpHsm;
    }

    public byte[] ComputeHmac(OtpHashMode mode, byte[] data)
    {
        if (mode == OtpHashMode.Sha256)
            return this.otpHsm.ComputeSha256HmacAgainstDerivedKey(this.derivedKeySerialNumber, data);
        else
            throw new ArgumentException("mode must be Sha256");
    }
}

Now the key is never in managed code and extremely safe from key leakage. OtpSharp in this case will only ever do the truncation/formatting of the HMAC into human readable one time passwords.

Then, this key can be given to a Totp/Hotp type and will be used for all calculation and verification operations

HsmKey myKey = ...
var totp = new Totp(myKey);

Updated