Domanda

sto cercando di avvolgere la mia mente intorno la generazione di un / non caso carattere 6 cifre sensibili scadenza password monouso.

La mia fonte è http://tools.ietf.org/html/rfc4226#section -5

In primo luogo la definizione dei parametri

C       8-byte counter value, the moving factor.  This counter
       MUST be synchronized between the HOTP generator (client)
       and the HOTP validator (server).

K       shared secret between client and server; each HOTP
       generator has a different and unique secret K.

T       throttling parameter: the server will refuse connections
       from a user after T unsuccessful authentication attempts.

Poi abbiamo l'algoritmo per generare il HOTP

As the output of the HMAC-SHA-1 calculation is 160 bits, we must
   truncate this value to something that can be easily entered by a
   user.

                   HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

Poi, abbiamo Tronca definito come

String = String[0]...String[19]
 Let OffsetBits be the low-order 4 bits of String[19]
 Offset = StToNum(OffsetBits) // 0 <= OffSet <= 15
 Let P = String[OffSet]...String[OffSet+3]
 Return the Last 31 bits of P

E poi un esempio è offerto per un HOTP 6 cifre

The following code example describes the extraction of a dynamic
binary code given that hmac_result is a byte array with the HMAC-
SHA-1 result:

    int offset   =  hmac_result[19] & 0xf ;
    int bin_code = (hmac_result[offset]  & 0x7f) << 24
       | (hmac_result[offset+1] & 0xff) << 16
       | (hmac_result[offset+2] & 0xff) <<  8
       | (hmac_result[offset+3] & 0xff) ;

Sono piuttosto in perdita nel tentativo di convertire questo in utile codice C # per la generazione di one-time password. Ho già il codice per la creazione di un HMAC scadenza nel seguente modo:

byte[] hashBytes = alg.ComputeHash(Encoding.UTF8.GetBytes(input));
byte[] result = new byte[8 + hashBytes.Length];

hashBytes.CopyTo(result, 8);
BitConverter.GetBytes(expireDate.Ticks).CopyTo(result, 0);

Solo che non sono sicuro di come andare a questo, a 6 cifre come proposto negli algoritmi di cui sopra.

È stato utile?

Soluzione

Si hanno due problemi qui:

  1. Se si sta generando alfanumerico, si non conforme al RFC - a questo punto, si può semplicemente prendere qualsiasi N byte e li trasformano in una stringa esadecimale e get alfanumerico. Oppure, convertirli in base 36 se si vuole az e 0-9. Sezione 5.4 della RFC ti dà il calc HOTP standard per un parametro Digit set (si noti che Digit è un parametro con C, K, e T). Se si sceglie di ignorare questa sezione, allora non c'è bisogno di convertire il codice -. Basta usare quello che vuoi

  2. Il tuo allineamento "risultato" di byte ha il tempo di scadenza semplicemente farcito nei primi 8 byte dopo hashing. Se il troncamento a alfanumerico a 6 cifre, non raccoglie questi insieme con le parti del hash, potrebbe anche non essere calcolato a tutti. E 'anche molto facile da "falso" o riproduzione - hash il segreto una volta, poi mettere tutto quello che vuoi zecche di fronte ad essa - non proprio una password una sola volta. Si noti che il parametro C nella RFC è destinato a soddisfare la finestra di scadenza e deve essere aggiunto all'ingresso del prima il calcolo del codice hash.

Altri suggerimenti

Per chiunque sia interessato, ho fatto capire un modo per costruire la scadenza nella password una sola volta. L'approccio è quello di utilizzare il tempo creato fino al minuto (ignorando secondi, millisecondi, ecc). Una volta che avete valore, utilizzare le zecche del DateTime come il vostro contatore, o variabile C.

otpLifespan è la mia vita HOTP in pochi minuti.

DateTime current = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 
    DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, 0);

for (int x = 0; x <= otpLifespan; x++)
{
    var result = NumericHOTP.Validate(hotp, key, 
        current.AddMinutes(-1 * x).Ticks);

    //return valid state if validation succeeded

    //return invalid state if the passed in value is invalid 
    //  (length, non-numeric, checksum invalid)
}

//return expired state

Il mio HOTP scadenza si estende dal mio HOTP numerico che ha un metodo di validazione statica che i controlli della lunghezza, assicura che è numerico, convalida il checksum se è usato, e, infine, confronta la HOTP passata con uno generato.

L'unico aspetto negativo di questo è che ogni volta che si convalida un HOTP scadenza, lo scenario caso peggiore è quello di controllare n + 1 valori HOTP dove n è la durata della vita in pochi minuti.

L'esempio di codice Java nel documento che delinea RFC 4226 è stata una mossa molto semplice in C #. L'unico pezzo ho dovuto mettere qualsiasi sforzo in riscrittura è stato il metodo di hashing.

private static byte[] HashHMACSHA1(byte[] keyBytes, byte[] text)
{
    HMAC alg = new HMACSHA1(keyBytes);

    return alg.ComputeHash(text);
}

Spero che questo aiuta chiunque altro tentativo di generare one-time password.

Questo frammento di codice dovrebbe fare quello che stai chiedendo:

  public class UniqueId
{
    public static string GetUniqueKey()
    {
        int maxSize = 6; // whatever length you want
        char[] chars = new char[62];
        string a;
        a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
           char[] chars = new char[a.Length];
        chars = a.ToCharArray();
        int size = maxSize;
        byte[] data = new byte[1];
        RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
        crypto.GetNonZeroBytes(data);
        size = maxSize;
        data = new byte[size];
        crypto.GetNonZeroBytes(data);
        StringBuilder result = new StringBuilder(size);
        foreach (byte b in data)
        { result.Append(chars[b % (chars.Length - 1)]); }
        return result.ToString();
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top