OtpSharp not working with google authenticator - c#

I've been trying to use OtpSharp along with Google Authenticator in an application I'm developing. However, I don't understand why the code produced by OtpSharp does not match that of Google Authenticator. I've even tried to correct the time input to OtpSharp according to my local OS without any luck. On another note, the pyotp library from python works just fine without any special effort.
Here is the code I'm using:
var bSharedKey = System.Text.Encoding.Unicode.GetBytes("TESTTESTTESTTEST");
//var correction = new TimeCorrection(DateTime.UtcNow.ToLocalTime());
//var totp = new Totp(bSharedKey, timeCorrection: correction);
var totp = new Totp(bSharedKey);
var realOtp = totp.ComputeTotp();
long timestep = 0;
var OTPmatch = totp.VerifyTotp(passwords[1], out timestep);

The problem was that instead of providing an arbitrary unicode key to the pyotp library (as well as to Google Authenticator), a Base32 string was needed as the input, which I assume was later decoded to a byte array and used by the library.
So I provided OtpSharp with the byte string representation of an arbitrary unicode string and used an online website to decode the unicode string to a base32 string, and used the base32 string in Google Authenticator.
To put it simply, Otpsharp requires a byte array to initialize a totp object, while pyotp needs you to provide it with a base32 string.

I used the following solution:
First
Choose a secret key.
e.g: 32 Chars
private const string SecretKey = "hfBhdVsbAWXmkdWrcnwezQqVLubqeRdq";
Second
Use an approach to generate QR code with your secret.
e.g:
https://stefansundin.github.io/2fa-qr/
How to generate a QR Code for Google Authenticator that correctly shows Issuer displayed above the OTP?
Point Key: You have to convert your secret key to Base32 to generate QR Code.
You can use https://emn178.github.io/online-tools/base32_encode.html to convert a string to base32 online
Third
Install OtpSharp nuget package.
Validate entered token as follows:
XXX: Valid Period In Seconds
private static bool Validate(string token)
{
var totp = new Totp(Encoding.UTF8.GetBytes(SecretKey));
return totp.VerifyTotp(DateTime.UtcNow.AddSeconds(XXX), token, out _, new VerificationWindow(2, 2));
}

Related

c# how to convert aes iv/key byte array into writeable string

I have a small inhouse app (and any advice on other methods is appreciated as well) where I utilize 2 token strings that I'd like to encrypt with aes. While this is a super small app and I don't think there's a huge risk on my local, I'd still like to encrypt them with something. My thought was that I'd:
have a file on my local with the iv/key string that I could read into my app upon running, it'd decrypt the token which is stored in the db and I could use it, and when I have to overwrite the token value I'd create a new aes/triple dev iv/key pair. the iv/key pair lives in a file (or the config of the app) and then the new encrypted token goes to my db.
The problem I'm having (i'm new to encryption) is that all of the tutorials show something like the following:
Aes aes = Aes.Create();
byte[] iv = aes.IV;
byte[] key = aes.Key;
However I'm looking to store the string value, and then when the app runs next and I pull the iv/key pair in I convert it back to byte[] to do the app work.
I tried:
string ivStr = Encoding.Default.GetString(iv);
However when I tried to convert it back to a byte[] and then pass it back through to the decryption tool it would just fail and told me the length of the array was incorrect.
Any advice on this would be appreciated.

C# SHA256 RSA Signing. How to take a string from byte[] sign?

I have to use some API, which service who has my certificate. They propably wants my sign to verify if it is the same with certificate on their server. Im not sure of that, but. In documentation it is instruction:
sign_base =
<?xml version="1.0" encoding="UTF-8"?> <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
//big XML, but i can't paste it here, because of NDA i signed (with pen ;-))
</ds:Reference> </ds:SignedInfo>
rsa_sha256(sign_base) =
113c7ed1e66e1ef77c0857d418928bdf1d3bdf27b8d06c7...40d1c0a259733ad0b1b2
// its long hash so i made "..." it is 516 characters there.
base64(rsa_sha256) = ETx+0eZuHvd8CFfUGJKL3x073ye40Gx7mB0.... tCxsg==
//it is a base64 of rsa_256 hash above.
Inspired by SoF questions i tried to use RSACryptoServiceProvider provider = new RSACryptoServiceProvider(); and then var signed = provider.SignData(sign_base, CryptoConfig.CreateFromName("SHA256")); but result gives me only bytes[]. When i decoded bytes[] to UTF-8 string result was unreadable "?????????..???" I can compare that with other signs, and do all stuff allowed by RSACryptoServiceProvider() but my question is:
They want to send this hash in request as parameter, so it is declared as base64 string. I have to send only base64 formatted message, but i have to count it first.
How to get string of this sign? Maybe there is mistake in my choices, and i am doing it wrong? If you give me help with different language than C# it will be helpfull too.
If I understand well and provided that your signature is correct, once you have it as byte[], you should be able to use Convert.ToBase64String(byte[] data) using System.Convert.ToBase64String.
Unlike what you did, you should be able to see a String looking like the example.

C# RSA Encrypt Private Decrypt Public?

Here is the problem I am trying to solve. Let's say I was releasing some web software built on ASP.NET MVC and I only wanted the end user to be able to add X users to the system. The software would be hosted on their servers.
I want to include an encrypted file that when the user tries to add a new user, it goes out and reads from the file an encrypted string. When the website decodes it, the clear text will be the number of allowed users.
What is the best/simplest way on my end to encrypt to generate this string on my end then decode it back to clear text in my application? Obviously I want to ensure that the end user cannot be spinning up their own encrypted string and just replace mine. I don't want to worry about having to try and obfuscate my source so that they would not be able to see how I decode the string.
Is it possible to encrypt with a private rsa key, then decrypt it with the public one? I haven't had luck with that in the code below:
var rsa = new RSACryptoServiceProvider();
var pubicKey = rsa.ToXmlString(false);
var privateKey = rsa.ToXmlString(true);
var test = "this string needs to be encrypted then decrypted";
var rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(privateKey);
var encryptedBytes = rsa2.Encrypt(Encoding.UTF8.GetBytes(test), false);
var encryptedString = Convert.ToBase64String(encryptedBytes);
var rsa3 = new RSACryptoServiceProvider();
rsa3.FromXmlString(pubicKey);
encryptedBytes = Convert.FromBase64String(encryptedString);
var decryptedString = Encoding.UTF8.GetString(rsa3.Decrypt(encryptedBytes, false));
You can use a signature strategy, where the private key is used to generate a signature that verifies that your message is authentic.
// Create message and signature on your end
string message = "Here is the license message";
var converter = new ASCIIEncoding();
byte[] plainText = converter.GetBytes(secret);
var rsaWrite = new RSACryptoServiceProvider();
var privateParams = rsaWrite.ExportParameters(true);
// Generate the public key / these can be sent to the user.
var publicParams = rsaWrite.ExportParameters(false);
byte[] signature =
rsaWrite.SignData(plainText, new SHA1CryptoServiceProvider());
// Verify from the user's side. Note that only the public parameters
// are needed.
var rsaRead = new RSACryptoServiceProvider();
rsaRead.ImportParameters(publicParams);
if (rsaRead.VerifyData(plainText,
new SHA1CryptoServiceProvider(),
signature))
{
Console.WriteLine("Verified!");
}
else
{
Console.WriteLine("NOT verified!");
}
This example was largely copied from Microsoft's site:
RSACryptoServiceProvider.SignData Method (Byte[], Object)
And here is web page that explains the concept:
Using RSA for Signing Messages
I think what you are looking for is digital signature. It doesn't matter if the content is encrypted or not, since the user has the (public) key to decrypt it. All that matters is if the content's source is you.
Since you have a config file I reckon it is XML, so you are looking for XMLDSIG.
You can easily achieve this using the SignedXml class in .Net. Then all you need to do is verify the signature when loading the config file. This method allows you to eaisly use any X509 certificates you may have. You can even embed the public key in the signed file, so the user does not need to install your cert (public key).
Your idea is correct, but I wonder about unforeseen consequences.
You state they will be running software on their servers, so this means they are hosting a service for themselves. But you also mention this service has to connect out tot he internet to add a user by validating with your server. What happens when the internet goes down or they want to have a secure system and a firewall blocks internet access to the servers? Will they completely lose their ability to function?
Just giving you a question to ask yourself :p
You don't use a public key to 'decrypt' the file. you can only decrypt the file with the private key.
In your case you could store the number of users as well a signature of the data which you create with your private key.
On the clients sever, you use your public key to verify the signature matches the data in the file (number of users)
However, it is possible that an advanced user could swap out your public key with their own and sign the file themselves.
As stated in your comment in the question, your approach is using a key from a client and a key from yourself. This will not work, as the prime numbers used in RSA are meant for use with only the corresponding private/public key.
What you need to do use your two keys and nothing from the client or the client's two keys and nothing of yours. For example,
You could sign it using your two keys by encrypting with your private key and allowing the client to decrypt using your public key.
You could encrypt it using your client's public key and have them decrypt is using their (the client's) private key.
Hope this helps!

Difference in SHA hashes between ruby and C#

I'm developing an application, that makes use of some REST web services.
It's technical documentation says that I should pass SHA256 hash of some string in the request.
In an example request (in the documentation) a string:
hn-Rw2ZHYwllUYkklL5Zo_7lWJVkrbShZPb5CD1expires=1893013926label[0]=any/somestatistics=1d,2d,7d,28d,30d,31d,lifetimestatus=upl,livetitle=a
After executing:
digest = Digest::SHA256.digest(string_to_sign)
signature = Base64::encode64(digest).chomp.gsub(/=+$/, '')
results in a hash:
YRYuN2zO+VvxISNp/vKQM5Cl6Dpzoin7mNES0IZJ06U
This example is in ruby, as the documentation is for ruby developers.
I'm developing my application in C# and for the exactly same string, when I execute:
byte[] rawHash = sha256.ComputeHash(rawRequest, 0, rawRequest.Length);
string friendlyHash = Convert.ToBase64String(rawHash);
and remove the trailing "=" signs, I get:
Vw8pl/KxnjcEbyHtfNiMikXZdIunysFF2Ujsow8hyiw
and therefore, the application fails to execute resulting in an signature mismatch error.
I've tried changing the encoding while converting the string to a byte array preceding the hashing and nothing changed.
Any ideas?
Based on the document here, you are missing a - (that is a dash) in your string. Seems that Acrobat helpfully removes it in a copy paste from the document...
Here is some code that I splatted together that gets the same value as the example (well it would if you trimmed the final =)
string s = "hn-Rw2ZH-YwllUYkklL5Zo_7lWJVkrbShZPb5CD1expires=1893013926label[0]=any/somestatistics=1d,2d,7d,28d,30d,31d,lifetimestatus=upl,livetitle=a";
SHA256Managed sh = new SHA256Managed();
byte[] request = System.Text.UTF8Encoding.UTF8.GetBytes(s);
sh.Initialize();
byte[] b4bbuff = sh.ComputeHash(request, 0, request.Length);
string b64 = Convert.ToBase64String(b4bbuff);

Digitally sign in PHP using private key, verify in C#

I am working on a feature that needs me to digitally sign a short string in PHP, and verify the string's signature in C#.
I would really like to use openssl_sign in PHP, because of its simplicity, but all the information I can find on Google indicates that this will not work.
There are some external libraries that claim to do this well, however as this is a hobby project I would rather not purchase such a library.
So what are the alternatives here? Full interoperability between C# and PHP is required. Libraries besides OpenSSL can be used.
I've done something very similar using Bouncy Castle Crypto APIs. It appears PHP openssl_sign uses SHA1 by default. If you are using anything other than the default you'll need to change the algorithm parameter for GetSigner.
string base64pubkey = "<!-- BASE64 representation of your pubkey from open ssl -->";
RsaKeyParameters pubKey = PublicKeyFactory.CreateKey(Convert.FromBase64String(base64pubkey)) as RsaKeyParameters;
byte[] signature = Convert.FromBase64String("<!-- BASE64 representation of your sig -->");
byte[] message = Encoding.ASCII.GetBytes("Something that has been signed");
ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
sig.Init(false, pubKey);
sig.BlockUpdate(message, 0, message.Length);
if (sig.VerifySignature(signature))
{
Console.WriteLine("all good!");
}
You may use to check the digital signature smth like this:
string publicKey = "some key";
// Verifying Step 1: Create the digital signature algorithm object
DSACryptoServiceProvider verifier = new DSACryptoServiceProvider();
// Verifying Step 2: Import the signature and public key.
verifier.FromXmlString(publicKey);
// Verifying Step 3: Store the data to be verified in a byte array
FileStream file = new FileStream(args[0], FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(file2);
byte[] data = reader.ReadBytes((int)file2.Length);
// Verifying Step 4: Call the VerifyData method
if (verifier.VerifyData(data, signature))
Console.WriteLine("Signature verified");
else
Console.WriteLine("Signature NOT verified");
reader.Close();
file.Close();
Is there a reason you need something as complex as SSL signing? Can't you just use a simple one-way hash like MD5/SHA-1 on the string? If all you're looking for is verification that the string wasn't tampered with, that should be sufficient.
So looking at this - this guy appears to have asymmetric signing and encrypting working between PHP and C#. Signing should not be a problem, SHA* and MD* are standard, and so it's very very unlikely that is going to not be compatible (although you should be looking at SHA256 as MD* and SHA1 are deprecated due to vulnerabilities)
We're missing some context as to why you need to sign it. You may not need to.
The important question is: what guarantees do you need from your data?
If all you need to do is verify the integrity of the data, a hash will do the job. If you need to verify where it's coming from, you need to sign it. If you need both, hash it, concatenate the payload with the hash, and sign the whole thing.
Regarding cross-platform libraries... you really should need to worry about it. A SHA1 is a SHA1 is a SHA1, no matter which library generated it. Same thing with generating and verifying digital signatures. Use what's easiest in PHP and use what's easiest in C#. If they're both set up correctly you shouldn't need to worry about it.

Categories

Resources