I'm making the equivalent java code for the code below. But I can make something that returns the same result for encodedString. What Java class can I use for achieve the same result?
//Set the Hash method to SHA1
HMAC hash;
switch (validation)
{
case MachineKeyValidation.MD5:
hash = new HMACMD5();
break;
case MachineKeyValidation.SHA1:
default:
hash = new HMACSHA1();
break;
}
//Get the hash validation key as an array of bytes
hash.Key = HexToByte(validationKey);
//Encode the password based on the hash key and
//converts the encrypted value into a string
encodedString = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
Thanks in advance!
:)
I found a solution for the translation code.
There was two main problem. When a request a HMACSHA1 I'm not talking about a SHA1 algorithm, but a HmacSHA1. And there is a difference between the encoding from Java and C#. I was using the correct key, and the correct algorithm, but the encoding was differente.
SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
// The big problem is difference between C# and Java encoding
byte[] rawHmac = mac.doFinal(data.getBytes("UTF-16LE"));
result = new String(Base64.encode(rawHmac));
See this question about computing hash functions in Java.
And look at the javadoc for java.security.MessageDigest.getInstance(String algorithm).
Edited to add:
Try running the following app to see what providers you have registered.
import java.security.Provider;
import java.security.Security;
public class SecurityTest {
public static void main(String[] args) {
Provider[] providers = Security.getProviders();
for (Provider p : providers) {
System.out.println(p.toString());
}
}
}
You should have at least a few Sun providers listed. If not, you may need to download some security libraries.
Related
This C# code:
private static string CreateHashKey(object myString)
{
byte[] buffer = JsonSerializer.SerializeToUtf8Bytes(myString);
var cryptoTransform = MD5.Create();
return BitConverter.ToString(cryptoTransform.ComputeHash(buffer));
}
When given the string "Bangalore", produces this hashed value: "92-E7-92-78-E7-D9-37-C1-AF-AC-D7-E6-B2-CD-B6-5E".
However, I cannot reproduce this in R, playing around a bit:
library(digest)
digest::digest(serialize("Bangalore", connection = NULL),"md5")
"e85798ec7dd5003d8d464f6c5d8de5c5"
digest::digest(serialize("Bangalore", connection = NULL,ascii = TRUE),"md5")
"5377a11b9792c774ddd726361c56d8f2"
digest::digest(charToRaw('Bangalore'),"md5")
"bf19f50fed3db016cb78cdb029db3034"
digest::digest(serialize(charToRaw('Bangalore'),connection = NULL,ascii = TRUE),"md5")
"be7696c777f9418e8e853084d6ddf0ae"
library(openssl)
md5("Bangalore") # "1bc99cb2f4153c2d0d8025ee5575b2a0"
This post suggests converting to bytes would fix the problem, but it hasn't so far...
Why do I get an different hash when running with python and C# the same key and message?
Deriving shared key using:
C# ECDiffieHellmanCng.DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey)
Kotlin KeyAgreement.generateSecret() followed by KeyAgreement.doPhase(key: Key!, lastPhase: Boolean)
Yields different results using curve "secp384r1".
Kotlin related links point to Kotlin for Android docs due to readability.
Simplified driver code to demonstrate the problem, assuming that C# .NET 7.0.1 console application is "Server" and Kotlin OpenJDK 19.0.1 application is "Client":
C#:
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
var listener = new TcpListener(IPAddress.Any, 13000);
listener.Start();
using var client = await listener.AcceptTcpClientAsync();
var sharedKey = await GetSharedKey(client, CancellationToken.None);
async Task<byte[]> GetSharedKey(TcpClient client, CancellationToken token)
{
//Generate ECDH key pair using secp384r1 curve
var ecdh = new ECDiffieHellmanCng(ECCurve.CreateFromFriendlyName("secp384r1"));
var publicKeyBytes = ecdh.ExportSubjectPublicKeyInfo();
Console.WriteLine($"Server Public Key: {Convert.ToBase64String(publicKeyBytes)}, " +
$"Length: {publicKeyBytes.Length}");
//Send the generated public key encoded in X.509 to client.
var stream = client.GetStream();
await stream.WriteAsync(publicKeyBytes, token);
//Receive client's public key bytes (X.509 encoding).
var otherPublicKeyBytes = new byte[publicKeyBytes.Length];
await stream.ReadExactlyAsync(otherPublicKeyBytes, 0, otherPublicKeyBytes.Length, token);
//Decode client's public key bytes.
var otherEcdh = new ECDiffieHellmanCng(ECCurve.CreateFromFriendlyName("secp384r1"));
otherEcdh.ImportSubjectPublicKeyInfo(otherPublicKeyBytes, out _);
Console.WriteLine($"Client Public Key: {Convert.ToBase64String(otherEcdh.ExportSubjectPublicKeyInfo())}, " +
$"Length: {otherEcdh.ExportSubjectPublicKeyInfo().Length}");
//Derive shared key.
var sharedKey = ecdh.DeriveKeyMaterial(otherEcdh.PublicKey);
Console.WriteLine($"Shared key: {Convert.ToBase64String(sharedKey)}, " +
$"Length: {sharedKey.Length}");
return sharedKey;
}
Kotlin:
import java.net.Socket
import java.security.KeyFactory
import java.security.KeyPairGenerator
import java.security.spec.ECGenParameterSpec
import java.security.spec.X509EncodedKeySpec
import java.util.*
import javax.crypto.KeyAgreement
fun main(args: Array<String>) {
val socket = Socket("127.0.0.1", 13000)
val sharedKey = getSharedKey(socket)
}
private fun getSharedKey(socket: Socket): ByteArray {
//Generate ECDH key pair using secp384r1 curve
val keyGen = KeyPairGenerator.getInstance("EC")
keyGen.initialize(ECGenParameterSpec("secp384r1"))
val keyPair = keyGen.generateKeyPair()
println("Client Public Key: ${Base64.getEncoder().encodeToString(keyPair.public.encoded)}, Length: ${keyPair.public.encoded.size}")
//Receive server's public key bytes (encoded in X.509)
val input = socket.getInputStream()
val publicKeyBytes = input.readNBytes(keyPair.public.encoded.size)
//Send the generated public key encoded in X.509 to server
val output = socket.getOutputStream()
output.write(keyPair.public.encoded)
// Decode the server's public key
val keySpec = X509EncodedKeySpec(publicKeyBytes)
val keyFactory = KeyFactory.getInstance("EC")
val otherPublicKey = keyFactory.generatePublic(keySpec)
println("Server Public Key: ${Base64.getEncoder().encodeToString(otherPublicKey.encoded)}, Length: ${otherPublicKey.encoded.size}")
// Use KeyAgreement to generate the shared key
val keyAgreement = KeyAgreement.getInstance("ECDH")
keyAgreement.init(keyPair.private)
keyAgreement.doPhase(otherPublicKey, true)
val sharedKey = keyAgreement.generateSecret()
println("Shared key: ${Base64.getEncoder().encodeToString(sharedKey)}, Length: ${sharedKey.size}")
return sharedKey
}
C# output:
Server Public Key: MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEqza/eiK23hQIEW5mVdqOc0hAP3tPqittlcvPa6bGdyJK9n64sg0qYyDoPsxJ4pf7ROLz0ACrDS7n/e5Z0J1SMsWpBDViS8NRBvKwa1rQjWdFR0wzRaeVg09LIjnGs4Mj, Length: 120
Client Public Key: MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE30zvqkljT4STiE6XfLtoN147WRGA92rz9BLZfbRkOjz7uNbQ3az46DdoyQi6+eON7QVjIf2H5LKBANSk+C5zRX6u8jjrbhURDHYBKgijOddy6mOaEwiADijD/NX72O2L, Length: 120
Shared key: /u+tZYHar4MxXfrn2oqPZAqhiB2pkSTRBZ12rUxdnII=, Length: 32
Kotlin output:
Client Public Key: MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE30zvqkljT4STiE6XfLtoN147WRGA92rz9BLZfbRkOjz7uNbQ3az46DdoyQi6+eON7QVjIf2H5LKBANSk+C5zRX6u8jjrbhURDHYBKgijOddy6mOaEwiADijD/NX72O2L, Length: 120
Server Public Key: MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEqza/eiK23hQIEW5mVdqOc0hAP3tPqittlcvPa6bGdyJK9n64sg0qYyDoPsxJ4pf7ROLz0ACrDS7n/e5Z0J1SMsWpBDViS8NRBvKwa1rQjWdFR0wzRaeVg09LIjnGs4Mj, Length: 120
Shared key: lErK9DJAutaJ4af7EYWvtEXicAwfSuadtQhlZxug26wGkgB/ce7hF6ihLL87Sqc3, Length: 48
It seems there are no problems with public key import/export, but C# side fails to even produce key of correct length (384 / 8 = 48).
Edit:
Somebody noticed that curiously enough C# "shared key" is Kotlin's shared key's SHA256 hash instead of the actual key.
I strongly suspect it's because of default key derivation function mismatch, but am not completely sure.
I would like to know what am I doing wrong and how to fix the issue.
Edit#2 - Solution:
As the accepted answer suggests - my suspicion is not entirely wrong. ECDiffieHellmanCng.DeriveKeyMaterial does a bit extra unnecessary work - namely returning derived key's SHA256 hash (by default) instead of the actual key and does not provide any means of returning the actual key.
For anyone that is interested in getting 48 byte shared key you will have to be content with it's SHA384 (or some other hashing algorithm) hash instead (or use BouncyCastle):
C# changes:
//Generate ECDH key pair using secp384r1 curve and change default key's hashing algorithm SHA256 to SHA384
var ecdh = new ECDiffieHellmanCng(ECCurve.CreateFromFriendlyName("secp384r1"))
{
HashAlgorithm = CngAlgorithm.Sha384
};
Kotlin changes:
val sharedKey = keyAgreement.generateSecret()
val sharedKeyHash = MessageDigest.getInstance("SHA384").digest(sharedKey)
println("Shared key SHA384 hash: ${Base64.getEncoder().encodeToString(sharedKeyHash)}, Length: ${sharedKeyHash.size}")
return sharedKeyHash
I also suggest to rename the GetSharedKey method to what it actually is - GetSharedKeysSHA384Hash.
The problem is that C# does do more than what is expected from the class. I.e. as usual, the .NET library doesn't adhere to the principle of least surprise:
The ECDiffieHellmanCng class enables two parties to exchange private key material even if they are communicating through a public channel. Both parties can calculate the same secret value, which is referred to as the secret agreement in the managed Diffie-Hellman classes. The secret agreement can then be used for a variety of purposes, including as a symmetric key. However, instead of exposing the secret agreement directly, the ECDiffieHellmanCng class does some post-processing on the agreement before providing the value. This post processing is referred to as the key derivation function (KDF); you can select which KDF you want to use and set its parameters through a set of properties on the instance of the Diffie-Hellman object.
Of course, the tw... developers that created the code don't exactly specify on what they perform the KDF, nor do they specify the default method used from the options that are shown. However, you can expect that they perform it on the X coordinate that is calculated by the Diffie-Hellman key agreement.
That said, it is not very clear from the Java class description either. The standard names document references RFC 3278, which points to the old Sec1 standard, section 6.1 using a broken link. Now Sec1 can still be downloaded, and if we look at section 6.1 we find a construction to encode integers to the a number of bytes that is the field size (and then take the required bytes). What however is returned is undoubtedly the same encoded X-coordinate that is the Input Keying Material to the KDF that Microsoft uses.
Phew, that was a lot of words to say that you have to take the result of the Kotlin code in bytes and then perform the SHA-256 algorithm on it. Oh, yeah, the SHA-256 default was guessed, it's also not specified as far as I can see by Microsoft, although they do expose the KeyDerivationFunction and HashAlgorithm properties and define the defaults for them.
There are some options to choose the parameters for the various KDF functions for ECDiffieHellmanCng, but you seem to be out of luck if you want to have the "raw" X-coordinate. If you want that you may need to use Bouncy Castle for C# but beware that it returns a raw integer for the X-coordinate instead of an encoding of a statically sized, unsigned, big endian integer.
I am working on an ASP.NET MVC 5 web application inside VS 2012 and I am using IIS 8 to deploy the web application.
I have a security token which I am using to call a third party WebAPI. Currently inside my controller class, I define and use the token as follows:
string token = "D12356";
string url = currentURL + "resources?AUTHTOKEN=" + token;
Is there is a way to encrypt this value, so if anyone accesses the code inside VS or anyone reverse engineers the .dll files on IIS they won't see the actual token value, but will instead see the encrypted value?
Is there is a way to encrypt this value, so if anyone accesses the code inside VS or anyone reverse engineers the .dll files on IIS they won't see the actual token value, but will instead see the encrypted value?
Well, yes, you can embed an encrypted value in the code, but the problem is that whoever decompiles the library will also see how you decrypt it.
Since you're talking about ASP.NET, your web.config is just as vulnerable as your source code, so there's no added security there.
The solution is to either store the value somewhere secure outside of your web app (secured database?), or use some external value as part of your decryption process, like a certificate or other private key value.
The following class has the encryption and decryption process, through which one can encrypt or decrypt its data with the provision of some values i.e.
Key = string / byte[] to encrypt or decrypt the input
Input = the user required field on which he wants to apply cryptography
Please write this class as follows:
namespace SomeNameSpace
{
public enum CryptType { ENCRYPT, DECRYPT }
public enum CryptTechnique { AES, RC2, RIJ, DES, TDES }
public class Cryptography
{
public object Crypt(CryptType EncryptOrDecrypt, CryptTechnique CryptographicTechnique, object Input, string Key)
{
try
{
SymmetricAlgorithm SymAlgo; //This class is parent of all classes in CryptTechnique enums
switch (CryptographicTechnique)
{
case CryptTechnique.AES:
SymAlgo = new AesManaged();
break;
case CryptTechnique.RC2:
SymAlgo = new RC2CryptoServiceProvider();
break;
case CryptTechnique.RIJ:
SymAlgo = new RijndaelManaged();
break;
case CryptTechnique.DES:
SymAlgo = new DESCryptoServiceProvider();
break;
case CryptTechnique.TDES:
SymAlgo = new TripleDESCryptoServiceProvider();
break;
default:
return false;
}
SymAlgo.Key = UTF8Encoding.UTF8.GetBytes(Key);
SymAlgo.Padding = PaddingMode.PKCS7;
SymAlgo.Mode = CipherMode.ECB;
ICryptoTransform ICT = null;
byte[] resultArray;
if(EncryptOrDecrypt == CryptType.ENCRYPT)
{
ICT = SymAlgo.CreateEncryptor();
}
else if(EncryptOrDecrypt == CryptType.DECRYPT)
{
ICT = SymAlgo.CreateDecryptor();
}
if (Input is string)
{
byte[] inputArray = UTF8Encoding.UTF8.GetBytes(Input as string);
resultArray = ICT.TransformFinalBlock(inputArray, 0, inputArray.Length);
SymAlgo.Clear();
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
else if (Input is byte[])
{
resultArray = ICT.TransformFinalBlock(Input as byte[], 0, (Input as byte[]).Length);
SymAlgo.Clear();
return resultArray;
}
return false;
}catch(Exception ex)
{
return ex.Message;
}
}
}
}
and in some controller where you want to encrypt or decrypt data, write there as
public ActionResult SomeAction()
{
string Key = "1234567890abcdef"; //key must have 16 chars, other wise you may get error "key size in not valid".
Password = "Secret";
Cryptography Crypt = new Cryptography();
EncryptedPassword = (string)Crypt.Crypt(CryptType.ENCRYPT, CryptTechnique.RIJ, Password, Key);
}
Here you will get the encrypted password in EncryptedPassword variable
I have a C# application that receives webhook notifications from PayPal and I want to verify the signature as described in PayPal docs:
https://developer.paypal.com/docs/integration/direct/rest-webhooks-overview/#event-types
The code snippet in the docs is for Java, not C#. The first thing I don't know is in which format the CRC32 should be appended (decimal, hex, ???). I have tried several variants and I have following code so far, always with VerifyData() returning false:
string transmissionSig = HttpContext.Request.Headers["PAYPAL-TRANSMISSION-SIG"];
string transmissionId = HttpContext.Request.Headers["PAYPAL-TRANSMISSION-ID"];
string transmissionTime = HttpContext.Request.Headers["PAYPAL-TRANSMISSION-TIME"];
string signatureAlgorithm = HttpContext.Request.Headers["PAYPAL-AUTH-ALGO"]; //signatureAlgorithm == "SHA256withRSA"
string certUrl = HttpContext.Request.Headers["PAYPAL-CERT-URL"];
uint crc = calculateCrc32(eventBody);
string expectedSignature = String.Format("{0}|{1}|{2}|{3}", transmissionId, transmissionTime, webhookId, crc);
string certData = new System.Net.WebClient().DownloadString(certUrl);
X509Certificate2 cert = new X509Certificate2(getBytes(certData));
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] signature = Convert.FromBase64String(transmissionSig);
byte[] expectedBytes = getBytes(expectedSignature);
bool verified = rsa.VerifyData(expectedBytes, CryptoConfig.MapNameToOID("SHA1"), signature);
What am I doing wrong?
UPDATE
I use this class for CRC calculation: https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/Security/Cryptography/Crc32.cs
Example eventBody (from webhook simulator):
{"id":"WH-2WR32451HC0233532-67976317FL4543714","create_time":"2014-10-23T17:23:52Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"A successful sale payment was made for $ 0.48 USD","resource":{"id":"80021663DE681814L","create_time":"2014-10-23T17:22:56Z","update_time":"2014-10-23T17:23:04Z","amount":{"total":"0.48","currency":"USD"},"payment_mode":"ECHECK","state":"completed","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","clearing_time":"2014-10-30T07:00:00Z","parent_payment":"PAY-1PA12106FU478450MKRETS4A","links":[{"href":"https://api.paypal.com/v1/payments/sale/80021663DE681814L","rel":"self","method":"GET"},{"href":"https://api.paypal.com/v1/payments/sale/80021663DE681814L/refund","rel":"refund","method":"POST"},{"href":"https://api.paypal.com/v1/payments/payment/PAY-1PA12106FU478450MKRETS4A","rel":"parent_payment","method":"GET"}]},"links":[{"href":"https://api.paypal.com/v1/notifications/webhooks-events/WH-2WR32451HC0233532-67976317FL4543714","rel":"self","method":"GET"},{"href":"https://api.paypal.com/v1/notifications/webhooks-events/WH-2WR32451HC0233532-67976317FL4543714/resend","rel":"resend","method":"POST"}]}
And it's CRC that I'm getting and appending to expectedSignature: 3561502039
you should get algorithm from the header in stead of hard-coding it. SHA256 is the currently supported algorithm I think.
I'm trying to encrypt some data in Mono C#, send it to a NodeJS server and decrypt it there. I'm trying to figure out what algorithms to use to match the two.
I send the encrypted string encoded with base64. So I do something like this in Javascript, where I know the key which was used to encrypt the data in my C# application:
var decipher = crypto.createDecipher('aes192',binkey, biniv);
var dec = decipher.update(crypted,'base64','utf8');
dec += decipher.final('utf8');
console.log("dec", dec);
In Mono I create my Cypher with:
using System.Security.Cryptography;
using (Aes aesAlg = Aes.Create("aes192"))
I need to pass the correct string to Aes.Create() in order to have it use the same algorithm, but I can't find what it should be. "aes192" is not correct it seems.
I don't need aes192 this was just a tryout. Suggest a different encryption flavor if it makes sense. Security is not much of an issue.
Here are links to .NET and Nodejs docs:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.aes.aspx
http://nodejs.org/api/crypto.html
This code works for my Node.js side, but please replace the static iv, otherwhise aes encryption would be useless.
var crypto = require('crypto');
function encrypt(data, key) {
key = key || new Buffer(Core.config.crypto.cryptokey, 'binary'),
cipher = crypto.createCipheriv('aes-256-cbc', key.toString('binary'), str_repeat('\0', 16));
cipher.update(data.toString(), 'utf8', 'base64');
return cipher.final('base64');
}
function decipher(data, key) {
key = key || new Buffer(Core.config.crypto.cryptokey, 'binary'),
decipher = crypto.createDecipheriv('aes-256-cbc', key.toString('binary'), str_repeat('\0', 16));
decipher.update(data, 'base64', 'utf8');
return decipher.final('utf8');
}
function str_repeat(input, multiplier) {
var y = '';
while (true) {
if (multiplier & 1) {
y += input;
}
multiplier >>= 1;
if (multiplier) {
input += input;
} else {
break;
}
}
return y;
}
I hope this helps You.
NOTE: You need to deliver an 265bit aka 32 character key for this algorithm to work.
POSSIBLE .NET SOLUTION: This may help you Example
You should simply write new AesManaged().
You don't need to call Create().
You then need to set Key and IV, then call CreateDecryptor() and put it in a CryptoStream.
It turned out to be a stupid mistake. I thought the create function in Node.js could take a variable argument count. Turns out you need to call the createDecipheriv() instead.
Just for the record, you can easily check the padding and mode by looking at those properties in the Aes object. The defaults are CBC and PKCS7. That padding is also used in nodejs crypto. So a for a 128 key size my code to decrypt a base64 encoded string would be:
var crypto = require('crypto');
var binkey = new Buffer(key, 'base64');
var biniv = new Buffer(iv, 'base64');
var decipher = crypto.createDecipheriv('aes-128-cbc', binkey, biniv);
var decrypted = decipher.update(crypted,'base64','utf8');
decrypted += decipher.final('utf8');
console.log("decrypted", decrypted);