C# Class for OATH/HMAC/SHA1 OTP (one time password)

Completado Publicado Aug 14, 2008 Pagado a la entrega
Completado Pagado a la entrega

I need a C# class with a single static method that can generate the proper one time password given a secret, a counter, and a length. The signature of the class should be something like this...

public class HmacOTP

{

public static String Generate(String secret, int counter)

{

String otp;

// do work

return otp;

}

}

===== Background =====

This is using the one time password (OTP) standard put out by the OATH consortium ([login to view URL]). This OTP technology is usually seen in hardware security tokens ([login to view URL]).

I have a short class in Ruby that does this.

## Deliverables

NOTE: this must be in managed code, all C#.

Also, there is an HMACSHA1 class in .NET that is probably the best starting point.

RFC for this can be found here ([login to view URL]).

===== Ruby equivalent =====

Here is a class in Ruby that does what I need...

=begin rdoc

Copyright (c) 2007, Vonage Holdings

All rights reserved.

Redistribution and use in source and binary forms, with or without

modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright

notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright

notice, this list of conditions and the following disclaimer in the

documentation and/or other materials provided with the distribution.

* Neither the name of Vonage Holdings nor the names of its

contributors may be used to endorse or promote products derived from this

software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

POSSIBILITY OF SUCH DAMAGE.

Authors: Michael DeCandia <mdecandia@[login to view URL]> and Stephen Becker <sbecker@[login to view URL]>

=== HOTP

The HOTP object can be used to calculate the HOTP value for any secret and count. The number of digits in the HOTP value is determined by an optional parameter. The default HOTP value is 6 digits long.

Creating an HOTP instance

h = [login to view URL]()

h.secret="12345678901234567890" # 20 byte key

h.count=0 # Where to start calculating

h.digits=6 # How many digits to return (length of the HOTP value)

puts([login to view URL]) # => "755224"

h.count=1 # Change the count

puts([login to view URL]) # => "287082"

Using HOTP as a class method

secret = "12345678901234567890"

count = 0

puts(HOTP::hotp(secret,count)) # => "755224"

=end

require 'openssl'

require 'logger'

#This implements HOTP: An HMAC-Based One-Time Password Algorithm as described in RFC 4226 ([login to view URL])

class HOTP

#The secret key in ascii (K)

attr_accessor :secret

#The count used to start the calculation (C)

attr_accessor :count

#The length of the HOTP value (Digit) (Defaults to 6)

attr_accessor :digits

#The default logger to use when reporting an error. (Defaults to STDERR)

@@logger = [login to view URL](STDERR)

#Creates an HOTP object

#* :secret is your secret key

#* :count is where to start your calculation

#* :digits is the length of the HOTP value

#

#Creating an HOTP instance

#

# h = [login to view URL]()

# h.secret="12345678901234567890" # 20 byte key

# h.count=0 # Where to start calculating

# h.digits=6 # How many digits to return (length of the HOTP value)

# puts([login to view URL]) # => "755224"

# h.count=1 # Change the count

# puts([login to view URL]) # => "287082"

#

#

#Using HOTP as a class method

#

# secret = "12345678901234567890"

# count = 0

# puts(HOTP::hotp(secret,count)) # => "755224"

#

def initialize(secret=nil,count=nil,digits=6)

begin

@secret = secret

@count = count

@digits = digits

rescue Exception => e

@@[login to view URL]{"Unable to initialize HOTP properly. Reason: #{e}"}

end

end

#Returns the HOTP value as a string

def update

begin

return calculate_hotp(@secret, @count, @digits)

rescue Exception => e

@@[login to view URL]{"Unable to update. Reason #{e}"}

end

end

alias_method :hotp, :update

#Returns the HOTP value as a string

def calculate_hotp(secret,count,digits=6)

return HOTP::hotp(secret,count,digits)

end

#Set the Logger object. By default this logs to STDERR

def self.logger=(logger)

@@logger = logger

end

#Class method that returns the HOTP value as a string

def [login to view URL](secret,count,digits=6)

begin

# The secret is plain text

# i.e "1234567891234567890"

# The count needs to be in hex so we need to convert it into a padded hex string

# i.e. 10 = "\x00\x00\x00\x00\x00\x00\x00\x0a"

# The digits are the number of digits to use when calculating the HOTP. (defaults to 6)

sha1_hash = OpenSSL::[login to view URL](OpenSSL::Digest::[login to view URL]("SHA1"), secret, string_to_hex_value(count,8))

#the last hex value is the offset

offset = sha1_hash[-1].[login to view URL]

#get the string in the offset range

dbc1 = sha1_hash[(offset*2)...((offset*2)+8)]

#31bits

dbc2 = [login to view URL] & "7fffffff".hex

hotp = dbc2%(10**digits.to_i)

hotp = sprintf("%0#{digits}d", hotp)

return hotp

rescue Exception => e

@@[login to view URL]{"Unable to calculate the HOTP value. Reason: #{e}"}

end

end

private

#Private class method that converts a string to a padded hex value

def self.string_to_hex_value(count,padding=nil,pad_char="0")

begin

return_string = ""

# Change count to an integer then base 16 convert to a string

# i.e. 10.to_s(16) = a

hex_count = count.to_i.to_s(16) #string

# Pad the resulting string with the pad_charater ("0" by default)

# i.e. Takes "a" and makes it "000000a"

# We multiply the padding by two since we evaluate the hex as two characters

# i.e. "a" in hex is "0a"

((padding.to_i*2) - [login to view URL]).times{[login to view URL](0,pad_char)} if padding

hex_count = "0"+hex_count if [login to view URL]%2==1

temp_char = "0"

[login to view URL](/../).each { |hexs|

temp_char[0]= [login to view URL]

return_string << temp_char

}

return return_string

rescue Exception => e

@@[login to view URL]{"Unable to convert string to hex. Reason #{e}"}

end

end

end

Programación en C# Seguridad informática Ingeniería Microsoft MySQL PHP Gestión de proyectos Arquitectura de software Verificación de software Seguridad web Windows Desktop

Nº del proyecto: #3140262

Sobre el proyecto

5 propuestas Proyecto remoto Activo Aug 14, 2008

Adjudicado a:

minuteckvw

See private message.

$85 USD en 14 días
(3 comentarios)
2.2

5 freelancers están ofertando un promedio de $141 por este trabajo

suryavijayvw

See private message.

$170 USD en 14 días
(124 comentarios)
5.7
specrentacoder

See private message.

$170 USD en 14 días
(14 comentarios)
5.0
dipankarsoft

See private message.

$127.5 USD en 14 días
(11 comentarios)
3.6
ezequielkinyo

See private message.

$153 USD en 14 días
(0 comentarios)
0.0