NBitcoin and generating addresses from xpub key - c#

I'm attempting to write an algorithm that generates public bitcoin addresses from a known xpubkey. The key I'm using for testing can be found at blockchain.info at
https://blockchain.info/xpub/xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKrhko4egpiMZbpiaQL2jkwSB1icqYh2cfDfVxdx4df189oLKnC5fSwqPfgyP3hooxujYzAu3fDVmz
I'm trying something like this to generate the address on the path 0,0,0, as below:
var pubkey = new ExtPubKey(Encoding.ASCII.GetBytes("6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKrhko4egpiMZbpiaQL2jkwSB1icqYh2cfDfVxdx4df189oLKnC5fSwqPfgyP3hooxujYzAu3fDVmz"));
Console.Writeline(pubkey.Derive(0).Derive(0).Derive(0).PubKey.GetAddress(Network.Main));
but I'm not fully understanding something because I get a 'Invalid point encoding 103' when trying to instantiate the ExtPubKey.

Via https://bitcointalk.org/index.php?topic=1242247.0
var pubkey = ExtPubKey.Parse("xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKrhko4egpiMZbpiaQL2jkwSB1icqYh2cfDfVxdx4df189oLKnC5fSwqPfgyP3hooxujYzAu3fDVmz");
var newAddress = pubkey.Derive(0).Derive(0).PubKey.GetAddress(Network.Main);
Console.WriteLine(newAddress);
Tested, generates expected first address.

You get invalid encoding, because you are trying to encode
"6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKrhko4egpiMZbpiaQL2jkwSB1icqYh2cfDfVxdx4df189oLKnC5fSwqPfgyP3hooxujYzAu3fDVmz"
instead of
"xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKrhko4egpiMZbpiaQL2jkwSB1icqYh2cfDfVxdx4df189oLKnC5fSwqPfgyP3hooxujYzAu3fDVmz"
You are missing xpub from the beginning.

Related

OtpSharp not working with google authenticator

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

Encrypt and decrypt parameter passed in on query string

I'm using (or attempting to!) the code for encrypting/decrypting a string found in this post Encrypting & Decrypting a String in C#.
If I call the functions directly, i.e.
StringHelper sHelp = new StringHelper();
var encryptMe = sHelp.EncryptString("comahony#centlaw.com", "myPassphrase");
Returns /sx3sL4DE7sM2klGKN3V+CQKdP02ZxbVxANjDh2yfGo= which is perfect
and if I then call
var decryptMe = sHelp.DecryptString(encryptMe, "myPassphrase");
Returns comahony#centlaw.com which again is what I'm after.
But if I pass the encrypted string on parameter on the querystring. i.e.
http://localhost:12345/sso?c=/sx3sL4DE7sM2klGKN3V+CQKdP02ZxbVxANjDh2yfGo=
and call the decryption function using:
var decryptMe = sHelp.DecryptString(Request.QueryString["c"].ToString(), "myPassphrase");
I'm getting the error of "Invalid length for a Base-64 char array or string."
From digging around on the net it appears to be something to do with the parameter needing to be URLEncoded but try as I might I just can't get past this error.
Could something shed some light please?
Thanks,
C

C# Json not handling accents correctly [duplicate]

The following code:
var text = (new WebClient()).DownloadString("http://export.arxiv.org/api/query?search_query=au:Freidel_L*&start=0&max_results=20"));
results in a variable text that contains, among many other things, the string
"$κ$-Minkowski space, scalar field, and the issue of Lorentz invariance"
However, when I visit that URL in Firefox, I get
$κ$-Minkowski space, scalar field, and the issue of Lorentz invariance
which is actually correct. I also tried
var data = (new WebClient()).DownloadData("http://export.arxiv.org/api/query?search_query=au:Freidel_L*&start=0&max_results=20");
var text = System.Text.UTF8Encoding.Default.GetString(data);
but this gave the same problem.
I'm not sure where the fault lies here. Is the feed lying about being UTF8-encoded, and the browser is smart enough to figure that out, but not WebClient? Is the feed properly UTF8-encoded, but WebClient is failing in some other way? What can I do to mitigate this?
It's not lying. You should set the webclient's encoding first before calling DownloadString.
using(WebClient webClient = new WebClient())
{
webClient.Encoding = Encoding.UTF8;
string s = webClient.DownloadString("http://export.arxiv.org/api/query?search_query=au:Freidel_L*&start=0&max_results=20");
}
As for why your alternative isn't working, it's because the usage is incorrect. Its should be:
System.Text.Encoding.UTF8.GetString()

coin.mx keeps giving me 403 forbidden error on my web request

I have been trying to make a query to the coin.mx site in a C# app, and I keep getting a 403 forbidden error. Their example uses python:
base64.b64encode(str(HMAC(YOUR_SECRET, PATH+'?'+S, sha512).digest())),
where PATH is a http path (e.x. "/api/v2/trader/info")
given my secret is a hex string of the form "d1e2a3d4", I calculate my signature as follows:
HMACSHA512 mHasher512 = new HMACSHA512(secret);
var path = "/api/v2/trader/info?nonce=123"
var msg = Encoding.ASCII.GetBytes( path );
var hash = mHasher512.ComputeHash(msg);
var hashb64 = Convert.ToBase64String(hash);
return hashb64;
Does this seem right?
For reference: https://coin.mx/coinmx_api_en.pdf
I was having the same issue and found this question while searching for a solution. I finally fixed the problem by removing ? in the path string. Try changing your path variable as follows (this is just for getting the hash string, the GET request still needs the ? of course).
var path = "/api/v2/trader/infononce=123"
Note the documentation seems incorrect. I figured this out by looking at the sample python code.

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!

Categories

Resources