Programmed in Visual Studio 2019 on Windows 10.
RFC 2898 encoding process from a .NET Framowork 4.7.2 project. to Xamarin.Form (.NET Standard 2.0) .
The original processing is as follows
var salt = "abcdefg";
var passWord = "password";
var iterations = 5;
var saltbyte = System.Text.Encoding.UTF8. GetBytes(salt);
var Rfc2898 = new System.Security.Cryptography. Rfc2898DeriveBytes(passWord, saltbyte, iterations, System.Security.Cryptography. HashAlgorithmName.SHA256);
Porting it will result in an error in Xamarin, because you can't specify a hash algorithm. You can't specify a hash algorithm.
var Rfc2898 = new System.Security.Cryptography. Rfc2898DeriveBytes(passWord, saltbyte, iterations);
How do I specify a hash algorithm in Xamarin?
Translated with www.DeepL.com/Translator (free version)
It seems like .NET Standard 2.0 doesn't provide the constructor with the HashAlgorithmName argument. It is however present in .NET Standard 2.1. You can easily change your library to use .NET Standard 2.1.
Otherwise, you will have to do that platform specifically instead. Xamarin.iOS and Xamarin.Android do have the constructor available.
So I would create a service to hash your passwords:
public interface IPasswordHasher
{
byte[] GetHashedPassword(string password, string salt, int keySize);
}
Then implement this on both Android and iOS and register it as a Xamarin.Forms DependencyService instance:
using System.Security.Cryptography;
using System.Text.Encoding;
using Xamarin.Forms;
[assembly: Dependency(typeof(MyAwesomeProject.iOS.Services.PasswordHasher))]
namespace MyAwesomeProject.iOS.Services
{
public class PasswordHasher : IPasswordHasher
{
public byte[] GetHashedPassword(string password, string salt, int keySize)
{
var saltbyte = UTF8.GetBytes(salt);
var rfc2898 = new Rfc2898DeriveBytes(password, saltbyte, 1000, HashAlgorithmName.SHA256);
return rfc2898.GetBytes(keySize);
}
}
}
Then when you need to use it as:
var bytes = DependencyService.Get<IDeviceOrientationService>().GetHashedPassword("password", "abcdefg", 20);
I highly recommend that you use more than 5 iterations for your PBKDF2 key derivation. The default is 1000, the higher the better. Of course on mobile, you may hit a performance limitation, but 5 is way too low.
Related
There are examples on the web on how to use bouncy castle library in Java to encrypt with RSA/ECB/OAEPWithSHA256AndMGF1Padding (Example is shown at breaking down RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING). However the bouncy castle library in C# seem to have deviated from Java library in that it is more explicit (hence requires more steps) and I am not able to figure out how to make it work for the above algorithm.
Would appreciate if some body can put a code sample together to encrypt a sample text using RSA/ECB/OAEPWithSHA256AndMGF1Padding.
Unfortunately, even the Java construct is ambiguous as it's open to different and incompatible interpretations, as is shown here. The Java Bouncycastle provider will do one thing with "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" and the Oracle provider will do a different thing.
You can and should specify exactly which behavior you want in both the Java and C# code.
C#:
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl;
namespace ScratchPad
{
class MainClass
{
public static void OaepEncryptExample()
{
var plain = Encoding.UTF8.GetBytes("The sun also rises.");
// Read in public key from file
var pemReader = new PemReader(File.OpenText(#"/Users/horton/tmp/key-examples/myserver_pub.pem"));
var rsaPub = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)pemReader.ReadObject();
// create encrypter
var encrypter = new OaepEncoding(new RsaEngine(), new Sha256Digest(), new Sha256Digest(), null);
encrypter.Init(true, rsaPub);
var cipher = encrypter.ProcessBlock(plain, 0, plain.Length);
Console.WriteLine(Convert.ToBase64String(cipher));
}
}
}
Java:
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.PEMParser;
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
public class OaepExample {
public static void oeapDecrypt() throws Exception {
final PEMParser pemParser = new PEMParser(new FileReader("/Users/horton/tmp/key-examples/myserver.p8"));
final PrivateKeyInfo privKey = (PrivateKeyInfo) pemParser.readObject();
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKey rsaPriv = (RSAPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(privKey.getEncoded()));
String cipher64 = "k8AYnTV6RgzQXmD7qn8QwucDXGjbYct+qMVvDmMELTnUcCOeTp82oJ0BryZyEEGXVSZ2BFg95e72Jt9ZAKWNcot2rZ0+POcda8pzY/MfdwIpnSJKITovk8xHL3B/jZDJyQrLMmNPjVV/uBFY2vgKhhLhJzzAJATcGpNdw+gF+XI=";
Cipher decrypter = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
OAEPParameterSpec parameterSpec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
PSource.PSpecified.DEFAULT);
decrypter.init(Cipher.DECRYPT_MODE, rsaPriv, parameterSpec);
final byte[] plain = decrypter.doFinal(Base64.getDecoder().decode(cipher64));
System.out.println(new String(plain, StandardCharsets.UTF_8));
}
}
I can't get the signature verification working, like it's described here. I'm using BouncyCastle.NetCore 1.8.1.3 and the project is a .NETCoreApp 1.0.
I'm developing on macOS 10.12.1, running dotnet core 1.0.4 and my server is running Ubuntu 16.04.2-x64 running the release version, build as netcore1.0 and ubuntu16.04-x64 app.
The rest of the system runs without problems, except the signature verification.
My validation always returns false.
Here is my service for validating the signature and body:
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace MySkill.Main.Services
{
public class CertificationValidationService : ICertificationValidationService
{
private const string Algorithm = "SHA1withRSA";
public async Task<bool> IsValidSiganture(Stream body, Stream certData, string signature)
{
var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(new StreamReader(certData));
var cert = (Org.BouncyCastle.X509.X509Certificate)pemReader.ReadObject();
using (var sr = new StreamReader(body))
{
var content = await sr.ReadToEndAsync();
var result = CheckRequestSignature(Encoding.UTF8.GetBytes(content), signature, cert);
return result;
}
}
private static bool CheckRequestSignature(byte[] bodyData, string signature, Org.BouncyCastle.X509.X509Certificate cert)
{
byte[] sig = Convert.FromBase64String(signature);
var pubKey = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)cert.GetPublicKey();
var signer = Org.BouncyCastle.Security.SignerUtilities.GetSigner(Algorithm);
signer.Init(false, pubKey);
signer.BlockUpdate(bodyData, 0, bodyData.Length);
return signer.VerifySignature(sig);
}
}
}
Does anybody have a tip, what i'm doing wrong or has used a different framework or apis?
From the code you shared it looks correct. Without seeing the rest of the code I am not sure if the Signature you got is correct. You can take a look at our C# code that passed certification at https://github.com/sophtron/Alexa-Skill-Sophtron and compare against your own to see if there are any differences.
I tried RSACryptoServiceProvider from .net library for signature validation and it had never worked. So I had to switch to BouncyCastle.1.8.1 too and it worked for me.
I have to dare with a web application developed in .NET 1.1 Framework, with no possibilities to upgrade to major versions.
Having said that, I need to encrypt a text using HMAC SHA256.
I see that System.Security.Cryptography namespace in .NET 1.1 provides me a way to has a message in SHA256. But I need to use HMAC (Hash-based Message Authentication Code) with SHA256, so I send not only the text to encrypt, but also a key.
I see that .NET Framework 2.0 and later has an specific class HMACSHA256 to manage this. But haven't found an implementation for .NET 1.1.
¿Any help?
Thanks in advance
You can add to your project the file from Microsoft:
namespace System.Security.Cryptography {
[System.Runtime.InteropServices.ComVisible(true)]
public class HMACSHA256 : HMAC {
//
// public constructors
//
public HMACSHA256 () : this (Utils.GenerateRandom(64)) {}
public HMACSHA256 (byte[] key) {
m_hashName = "SHA256";
#if FEATURE_CRYPTO
m_hash1 = GetHashAlgorithmWithFipsFallback(() => new SHA256Managed(), () => HashAlgorithm.Create("System.Security.Cryptography.SHA256CryptoServiceProvider"));
m_hash2 = GetHashAlgorithmWithFipsFallback(() => new SHA256Managed(), () => HashAlgorithm.Create("System.Security.Cryptography.SHA256CryptoServiceProvider"));
#else
m_hash1 = new SHA256Managed();
m_hash2 = new SHA256Managed();
#endif // FEATURE_CRYPTO
HashSizeValue = 256;
base.InitializeKey(key);
}
}
}
It seems that all calls are based on class that exists in .Net 1.1
I'm making a Windows application, which you need to log into first.
The account details consist of username and password, and they need to be saved locally.
It's just a matter of security, so other people using the same computer can't see everyone's personal data.
What is the best/most secure way to save this data?
I don't want to use a database, so I tried some things with Resource files.
But since I'm kind of new with this, I'm not entirely sure of what I'm doing and where I should be looking for a solution.
If you are just going to verify/validate the entered user name and password, use the Rfc2898DerivedBytes class (also known as Password Based Key Derivation Function 2 or PBKDF2). This is more secure than using encryption like Triple DES or AES because there is no practical way to go from the result of RFC2898DerivedBytes back to the password. You can only go from a password to the result. See Is it ok to use SHA1 hash of password as a salt when deriving encryption key and IV from password string? for an example and discussion for .Net or String encrypt / decrypt with password c# Metro Style for WinRT/Metro.
If you are storing the password for reuse, such as supplying it to a third party, use the Windows Data Protection API (DPAPI). This uses operating system generated and protected keys and the Triple DES encryption algorithm to encrypt and decrypt information. This means your application does not have to worry about generating and protecting the encryption keys, a major concern when using cryptography.
In C#, use the System.Security.Cryptography.ProtectedData class. For example, to encrypt a piece of data, use ProtectedData.Protect():
// Data to protect. Convert a string to a byte[] using Encoding.UTF8.GetBytes().
byte[] plaintext;
// Generate additional entropy (will be used as the Initialization vector)
byte[] entropy = new byte[20];
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(entropy);
}
byte[] ciphertext = ProtectedData.Protect(plaintext, entropy,
DataProtectionScope.CurrentUser);
Store the entropy and ciphertext securely, such as in a file or registry key with permissions set so only the current user can read it. To get access to the original data, use ProtectedData.Unprotect():
byte[] plaintext= ProtectedData.Unprotect(ciphertext, entropy,
DataProtectionScope.CurrentUser);
Note that there are additional security considerations. For example, avoid storing secrets like passwords as a string. Strings are immutable, being they cannot be notified in memory so someone looking at the application's memory or a memory dump may see the password. Use SecureString or a byte[] instead and remember to dispose or zero them as soon as the password is no longer needed.
I have used this before and I think in order to make sure credential persist and in a best secure way is
you can write them to the app config file using the ConfigurationManager class
securing the password using the SecureString class
then encrypting it using tools in the Cryptography namespace.
This link will be of great help I hope : Click here
I wanted to encrypt and decrypt the string as a readable string.
Here is a very simple quick example in C# Visual Studio 2019 WinForms based on the answer from #Pradip.
Right click project > properties > settings > Create a username and password setting.
Now you can leverage those settings you just created. Here I save the username and password but only encrypt the password in it's respectable value field in the user.config file.
Example of the encrypted string in the user.config file.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<secure_password_store.Properties.Settings>
<setting name="username" serializeAs="String">
<value>admin</value>
</setting>
<setting name="password" serializeAs="String">
<value>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAQpgaPYIUq064U3o6xXkQOQAAAAACAAAAAAAQZgAAAAEAACAAAABlQQ8OcONYBr9qUhH7NeKF8bZB6uCJa5uKhk97NdH93AAAAAAOgAAAAAIAACAAAAC7yQicDYV5DiNp0fHXVEDZ7IhOXOrsRUbcY0ziYYTlKSAAAACVDQ+ICHWooDDaUywJeUOV9sRg5c8q6/vizdq8WtPVbkAAAADciZskoSw3g6N9EpX/8FOv+FeExZFxsm03i8vYdDHUVmJvX33K03rqiYF2qzpYCaldQnRxFH9wH2ZEHeSRPeiG</value>
</setting>
</secure_password_store.Properties.Settings>
</userSettings>
</configuration>
Full Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace secure_password_store
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Exit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void Login_Click(object sender, EventArgs e)
{
if (checkBox1.Checked == true)
{
Properties.Settings.Default.username = textBox1.Text;
Properties.Settings.Default.password = EncryptString(ToSecureString(textBox2.Text));
Properties.Settings.Default.Save();
}
else if (checkBox1.Checked == false)
{
Properties.Settings.Default.username = "";
Properties.Settings.Default.password = "";
Properties.Settings.Default.Save();
}
MessageBox.Show("{\"data\": \"some data\"}","Login Message Alert",MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void DecryptString_Click(object sender, EventArgs e)
{
SecureString password = DecryptString(Properties.Settings.Default.password);
string readable = ToInsecureString(password);
textBox4.AppendText(readable + Environment.NewLine);
}
private void Form_Load(object sender, EventArgs e)
{
//textBox1.Text = "UserName";
//textBox2.Text = "Password";
if (Properties.Settings.Default.username != string.Empty)
{
textBox1.Text = Properties.Settings.Default.username;
checkBox1.Checked = true;
SecureString password = DecryptString(Properties.Settings.Default.password);
string readable = ToInsecureString(password);
textBox2.Text = readable;
}
groupBox1.Select();
}
static byte[] entropy = Encoding.Unicode.GetBytes("SaLtY bOy 6970 ePiC");
public static string EncryptString(SecureString input)
{
byte[] encryptedData = ProtectedData.Protect(Encoding.Unicode.GetBytes(ToInsecureString(input)),entropy,DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encryptedData);
}
public static SecureString DecryptString(string encryptedData)
{
try
{
byte[] decryptedData = ProtectedData.Unprotect(Convert.FromBase64String(encryptedData),entropy,DataProtectionScope.CurrentUser);
return ToSecureString(Encoding.Unicode.GetString(decryptedData));
}
catch
{
return new SecureString();
}
}
public static SecureString ToSecureString(string input)
{
SecureString secure = new SecureString();
foreach (char c in input)
{
secure.AppendChar(c);
}
secure.MakeReadOnly();
return secure;
}
public static string ToInsecureString(SecureString input)
{
string returnValue = string.Empty;
IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
try
{
returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
return returnValue;
}
private void EncryptString_Click(object sender, EventArgs e)
{
Properties.Settings.Default.password = EncryptString(ToSecureString(textBox2.Text));
textBox3.AppendText(Properties.Settings.Default.password.ToString() + Environment.NewLine);
}
}
}
DPAPI is just for this purpose. Use DPAPI to encrypt the password the first time the user enters is, store it in a secure location (User's registry, User's application data directory, are some choices). Whenever the app is launched, check the location to see if your key exists, if it does use DPAPI to decrypt it and allow access, otherwise deny it.
This only works on Windows, so if you are planning to use dotnet core cross-platform, you'll have to look elsewhere. See https://github.com/dotnet/corefx/blob/master/Documentation/architecture/cross-platform-cryptography.md
For simple scenarios can also use Windows Credential Management API using C# wrapper CredentialManagement. It gives single place to store/retrieve passwords, easy to change.
https://stackoverflow.com/a/32550674/1129978
We're trying to generate an X509 certificate (including the private key) programmatically using C# and the BouncyCastle library. We've tried using some of the code from this sample by Felix Kollmann but the private key part of the certificate returns null. Code and unit test are as below:
using System;
using System.Collections;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
namespace MyApp
{
public class CertificateGenerator
{
/// <summary>
///
/// </summary>
/// <remarks>Based on <see cref="http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx"/></remarks>
/// <param name="subjectName"></param>
/// <returns></returns>
public static byte[] GenerateCertificate(string subjectName)
{
var kpgen = new RsaKeyPairGenerator();
kpgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 1024));
var kp = kpgen.GenerateKeyPair();
var gen = new X509V3CertificateGenerator();
var certName = new X509Name("CN=" + subjectName);
var serialNo = BigInteger.ProbablePrime(120, new Random());
gen.SetSerialNumber(serialNo);
gen.SetSubjectDN(certName);
gen.SetIssuerDN(certName);
gen.SetNotAfter(DateTime.Now.AddYears(100));
gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
gen.SetSignatureAlgorithm("MD5WithRSA");
gen.SetPublicKey(kp.Public);
gen.AddExtension(
X509Extensions.AuthorityKeyIdentifier.Id,
false,
new AuthorityKeyIdentifier(
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(kp.Public),
new GeneralNames(new GeneralName(certName)),
serialNo));
gen.AddExtension(
X509Extensions.ExtendedKeyUsage.Id,
false,
new ExtendedKeyUsage(new ArrayList() { new DerObjectIdentifier("1.3.6.1.5.5.7.3.1") }));
var newCert = gen.Generate(kp.Private);
return DotNetUtilities.ToX509Certificate(newCert).Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, "password");
}
}
}
Unit test:
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MyApp
{
[TestClass]
public class CertificateGeneratorTests
{
[TestMethod]
public void GenerateCertificate_Test_ValidCertificate()
{
// Arrange
string subjectName = "test";
// Act
byte[] actual = CertificateGenerator.GenerateCertificate(subjectName);
// Assert
var cert = new X509Certificate2(actual, "password");
Assert.AreEqual("CN=" + subjectName, cert.Subject);
Assert.IsInstanceOfType(cert.PrivateKey, typeof(RSACryptoServiceProvider));
}
}
}
Just to clarify, an X.509 certificate does not contain the private key. The word certificate is sometimes misused to represent the combination of the certificate and the private key, but they are two distinct entities. The whole point of using certificates is to send them more or less openly, without sending the private key, which must be kept secret. An X509Certificate2 object may have a private key associated with it (via its PrivateKey property), but that's only a convenience as part of the design of this class.
In your first BouncyCastle code example, newCert is really just the certificate and DotNetUtilities.ToX509Certificate(newCert) is built from the certificate only.
Considering that the PKCS#12 format requires the presence of a private key, I'm quite surprised that the following part even works (considering you're calling it on a certificate which can't possibly know the private key):
.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12,
"password");
(gen.Generate(kp.Private) signs the certificate using the private key, but doesn't put the private key in the certificate, which wouldn't make sense.)
If you want your method to return both the certificate and the private key you could either:
Return an X509Certificate2 object in which you've initialized the PrivateKey property
Build a PKCS#12 store and returns its byte[] content (as if it was a file). Step 3 in the link you've sent (mirror) explains how to build a PKCS#12 store.
Returning the byte[] (DER) structure for the X.509 certificate itself will not contain the private key.
If your main concern (according to your test case) is to check that the certificate was built from an RSA key-pair, you can check the type of its public key instead.
I realise this is an old post but I found these excellent articles which go through the process:
Using Bouncy Castle from .NET