I have two methods, where I need to convert string to base64 at begin and reverse this operation at the end. Problem is when my input string lenght is not divisible by 4 an conversion method throws exception.
public class Hashing
{
public string Encrypt(string encrypted)
{
byte[] byteData = Convert.FromBase64String(encrypted);
byte[] byteResult = Encrypt(byteData); // pt.1
return Convert.ToBase64String(byteResult);
}
public string Decrypt(string decrypted)
{
byte[] byteData = Convert.FromBase64String(decrypted);
byte[] byteResult = Decrypt(byteData); //pt.2
return Convert.ToBase64String(byteResult);
}
/*
...
*/
}
class Program
{
static void Main(string[] args)
{
Hashing cryptographyContext = new Hashing();
var cryptoTest = "123456789"; //someStringThatNotGonnaBeConverted;
string enc = cryptographyContext.Encrypt(password);
string dec = cryptographyContext.Decrypt(enc);
Console.WriteLine(dec);
Console.ReadLine();
}
}
Problem is I need base64 format at input of Decrypt and Encrypt methods (these at pt. 1 and 2) And I need returning strings from these methods. Do someone have an idea how to workaround this behaviour?
You are using base-64 incorrectly; base-64 translates:
forwards, arbitrary byte[] to structured string
backwards, structured string to the original byte[]
Conversely, a regular text encoding works the other way:
forwards, arbitrary string to structured byte[]
backwards, structured byte[] to the original string
You are trying to use base-64 to get a byte[] from an arbitrary string, which isn't a thing that it does. For that, you want a regular text encoding, such as UTF-8. Try using Encoding.UTF8.GetBytes() etc instead for one half, and base-64 for the other:
public string Encrypt(string plainText)
{
byte[] byteData = Encoding.UTF8.GetBytes(plainText);
byte[] byteResult = Encrypt(byteData);
return Convert.ToBase64String(byteResult);
}
public string Decrypt(string cipherText)
{
byte[] byteData = Convert.FromBase64String(cipherText);
byte[] byteResult = Decrypt(byteData);
return Encoding.UTF8.GetString(byteResult);
}
Related
The text ZIRT which i encrypt by base64 this way
public static string encrypt(string ToEncrypt)
{
return Convert.ToBase64String(Encoding.ASCII.GetBytes(ToEncrypt));
}
after encrypt the text becomes V2tsU1ZB and when i try to decrypt using the below function
public static string decrypt(string cypherString)
{
//return Encoding.ASCII.GetString(Convert.FromBase64String(cypherString));
byte[] data = Convert.FromBase64String(cypherString);
string decodedString = Encoding.UTF8.GetString(data);
return decodedString;
}
then i am getting this text WklSVA but it suppose to be ZIRT
Please tell me what is wrong in my code ?
I am giving more code which fail to decrypt text
private void button1_Click(object sender, EventArgs e)
{
string strTxt = "ZIRT";
string ss = EnryptString(strTxt);
string ss1 = EnryptString(ss);
}
public string DecryptString(string encrString)
{
byte[] b;
string decrypted;
try
{
b = Convert.FromBase64String(encrString);
decrypted = System.Text.ASCIIEncoding.ASCII.GetString(b);
}
catch (FormatException fe)
{
decrypted = "";
}
return decrypted;
}
public string EnryptString(string strEncrypted)
{
byte[] b = System.Text.ASCIIEncoding.ASCII.GetBytes(strEncrypted);
string encrypted = Convert.ToBase64String(b);
return encrypted;
}
There is double encoding of the strings that explain the incorrect result. You are also using different text encodings when encrypting and decrypting. ASCII vs UTF8, this should be the same.
The following example provides the result I would expect:
byte[] b = System.Text.ASCIIEncoding.UTF8.GetBytes("test abc");
string base64Encoded = Convert.ToBase64String(b);
b = Convert.FromBase64String(base64Encoded);
Console.WriteLine( System.Text.ASCIIEncoding.UTF8.GetString(b));
// "test abc"
As mentioned in the comments, this is not encryption, but encoding.
When i try to decrypt my data using the Google KMS i am getting this error. Below is my code for the decryption. The error is hitting on the line where there is string plaintext. Thanks in advance
Code
public static string Encrypt(string plaintext)
{
KeyManagementServiceClient client = KeyManagementServiceClient.Create();
//projects/progforthecloudt2020/locations/global/keyRings/pfckeyring001/cryptoKeys/pfckeys
CryptoKeyName kn = CryptoKeyName.FromUnparsed(new
Google.Api.Gax.UnparsedResourceName("GOOGLE RESOURCE ID REMOVED"));
string cipher = client.Encrypt(kn, ByteString.CopyFromUtf8(plaintext)).Ciphertext.ToBase64();
return cipher;
}
public static string Decrypt(string cipher)
{
KeyManagementServiceClient client = KeyManagementServiceClient.Create();
CryptoKeyName kn = CryptoKeyName.FromUnparsed(new Google.Api.Gax.UnparsedResourceName("GOOGLE RESOURCE ID REMOVED"));
string plaintext = client.Decrypt(kn, ByteString.CopyFromUtf8(cipher)).Plaintext.ToBase64();
return plaintext;
}
Error
Grpc.Core.RpcException: 'Status(StatusCode=InvalidArgument, Detail="Decryption failed: the ciphertext is invalid.")'
You’re base64 encoding the result of your encryption call, but then you aren’t base64 decoding it in your decrypt call. You shouldn’t need to base64 encode the data.
public static void Encrypt(string projectId, string locationId, string keyRingId, string cryptoKeyId, string plaintextFile, string ciphertextFile)
{
KeyManagementServiceClient client = KeyManagementServiceClient.Create();
CryptoKeyName cryptoKeyName =
new CryptoKeyName(projectId, locationId, keyRingId, cryptoKeyId);
byte[] plaintext = File.ReadAllBytes(plaintextFile);
EncryptResponse result = client.Encrypt(cryptoKeyName, ByteString.CopyFrom(plaintext));
// Output encrypted data to a file.
File.WriteAllBytes(ciphertextFile, result.Ciphertext.ToByteArray());
Console.Write($"Encrypted file created: {ciphertextFile}");
}
public static void Decrypt(string projectId, string locationId, string keyRingId, string cryptoKeyId, string ciphertextFile, string plaintextFile)
{
KeyManagementServiceClient client = KeyManagementServiceClient.Create();
CryptoKeyName cryptoKeyName =
new CryptoKeyName(projectId, locationId, keyRingId, cryptoKeyId);
byte[] ciphertext = File.ReadAllBytes(ciphertextFile);
DecryptResponse result = client.Decrypt(cryptoKeyName, ByteString.CopyFrom(ciphertext));
// Output decrypted data to a file.
File.WriteAllBytes(plaintextFile, result.Plaintext.ToByteArray());
Console.Write($"Decrypted file created: {plaintextFile}");
}
I'm trying to encryption and decrpytion process between C# and PHP.
My C# code:
this.EncryptData("123456", 1024, this.PublicKey);
public byte[] Encrypt(byte[] byte_0, int keysize, string publicKey)
{
byte[] numArray;
using (RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider(keysize))
{
rSACryptoServiceProvider.FromXmlString(publicKey);
numArray = rSACryptoServiceProvider.Encrypt(byte_0, this.bool_0);
}
return numArray;
}
public string EncryptData(string string_0, int keysize, string publicKey)
{
string base64String;
try
{
byte[] numArray = this.Encrypt(Encoding.UTF8.GetBytes(string_0), keysize, publicKey);
base64String = Convert.ToBase64String(numArray);
}
catch (Exception exception)
{
base64String = string.Empty;
}
return base64String;
}
public byte[] Decrypt(byte[] byte_0, int keysize, string Key)
{
byte[] numArray;
using (RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider(keysize))
{
rSACryptoServiceProvider.FromXmlString(Key);
numArray = rSACryptoServiceProvider.Decrypt(byte_0, this.bool_0);
}
return numArray;
}
public string DecryptData(string string_0, int keysize, string Key)
{
string str;
try
{
byte[] numArray = this.Decrypt(Convert.FromBase64String(string_0), keysize, Key);
str = Encoding.UTF8.GetString(numArray);
}
catch (Exception exception)
{
str = string.Empty;
}
return str;
}
and my PHP: lib(https://github.com/membersuite/sdk-php/blob/master/APISample/SSOWithSDK/phpseclib/Crypt/RSA_XML.php)
$rsa = new Crypt_RSA_XML();
$plaintext = '123456';
$rsa->loadKeyfromXML($publicKey);
$ciphertext = base64_encode(strrev($rsa->encrypt($plaintext)));
code after PHP encrypt cant decrypt by c# code. anyone can help?
Although Microsoft uses little endian notation for numbers, RSA has been defined by PKCS#1 / RFC 3447. That explicitly defines how to do padding and such, but it also defines how the resulting octet string should look like using I2OSP or the integer-to-octet-string primitive. This primitive specifies the output as fixed size (key size) byte array in big endian format. This is also the encoding that PHP uses, so you should not reverse the output.
In other words, you should not have to use strrev.
I am developing a REST API. Client puts it's user name and password in authorization header of HttpClient after encrypting it with public key of Server. Username and password will always consist of alphabets and number which means it can be represented in ASCII.
I am using this code for encryption.
string encrypted = Encrypt (someText, crypto);
public static string Encrypt (string plainText, RSACryptoServiceProvider crypto)
{
var plainData = GetBytes (plainText);
var encryptedData = crypto.Encrypt (plainData, true);
return GetString (encryptedData);
}
public static byte[] GetBytes (string str)
{
var bytes = new byte[str.Length * sizeof (char)];
Buffer.BlockCopy (str.ToCharArray (), 0, bytes, 0, bytes.Length);
return bytes;
}
public static string GetString (byte[] bytes)
{
var chars = new char[bytes.Length / sizeof (char)];
Buffer.BlockCopy (bytes, 0, chars, 0, bytes.Length);
return new string (chars);
}
Problem is that I get this string after encryption
꠨屰欧㼡⭮鍴⬎㔾䐛え멩戻덒郝㬭ே䉚ꑰ䵇᷹᷶虣ⱒ̿ঊࠎ飳枹鬭쉦폩��ᤫ槺愐丄裘ډ졽肟䷋ٱ᮷튼쁡鮤붮飦ꃨ◡뉋⭠夏旻浨᠏რ
I can't send these Unicode characters in the authorization header. Is there any way to get the encrypted text in ASCII so that it can easily be sent through HttpClient?
You can base64 encode it. Base64 encoding produces a string that is suitable for sending over a transport that supports ASCII strings.
public static string Encrypt (string plainText, RSACryptoServiceProvider crypto)
{
var plainData = GetBytes (plainText);
var encryptedData = crypto.Encrypt (plainData, true);
return Convert.ToBase64String (encryptedData);
}
Btw, I would replace your custom GetBytes method for converting the string to an array of bytes with Encoding.GetBytes; which is the built in and preferred method of doing that. For instance:
var plainData = System.Text.Encoding.UTF8.GetBytes(plainText);
I have the following code in Java:
byte[] secretKey = secretAccessKey.getBytes("UTF-8");
SecretKeySpec signingKey = new SecretKeySpec(secretKey, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] bytes = data.getBytes("UTF-8");
byte[] rawHmac = mac.doFinal(bytes);
String result = javax.xml.bind.DatatypeConverter.printBase64Binary(rawHmac);
and the following code in C#:
UTF8Encoding enc = new UTF8Encoding();
byte[] secretKey = enc.GetBytes(secretAccessKey);
HMACSHA256 hmac = new HMACSHA256(secretKey);
hmac.Initialize();
byte[] bytes = enc.GetBytes(data);
byte[] rawHmac = hmac.ComputeHash(bytes);
string result = Convert.ToBase64String(rawHmac);
The byte arrays "secretKey" and "bytes" are equivalent but the byte array "rawHmac" is different, and the string "result" is different. Can anyone see why?
Don't do this:
byte[] bytes = data.getBytes();
That will use the platform default encoding to convert a string to a byte array. That can vary between platform, whereas you want something repeatable. I would suggest UTF-8:
byte[] bytes = data.getBytes("UTF-8");
(Do the same for the key, of course.)
You should then use the same encoding in your C# - not ASCII, unless you really want to not handle non-ASCII characters.
byte[] bytes = Encoding.UTF8.GetBytes(data);
It's also not clear how you're comparing the results afterwards - don't forget that byte is signed in Java, but unsigned in C#. It's probably simplest to convert the hash to hex or base64 for comparison purposes.
EDIT: I strongly suspect the last part was the problem - comparing the results.
Here are two short but complete programs (using the iharder.net base64 converter in Java) which produce the same base64 output:
Java:
import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class Test {
public static void main (String[] args) throws Exception {
String secretAccessKey = "mykey";
String data = "my data";
byte[] secretKey = secretAccessKey.getBytes();
SecretKeySpec signingKey = new SecretKeySpec(secretKey, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] bytes = data.getBytes();
byte[] rawHmac = mac.doFinal(bytes);
System.out.println(Base64.encodeBytes(rawHmac));
}
}
C#:
using System;
using System.Security.Cryptography;
using System.Text;
class Test
{
static void Main()
{
String secretAccessKey = "mykey";
String data = "my data";
byte[] secretKey = Encoding.UTF8.GetBytes(secretAccessKey);
HMACSHA256 hmac = new HMACSHA256(secretKey);
hmac.Initialize();
byte[] bytes = Encoding.UTF8.GetBytes(data);
byte[] rawHmac = hmac.ComputeHash(bytes);
Console.WriteLine(Convert.ToBase64String(rawHmac));
}
}
Output from both:
ivEyFpkagEoghGnTw/LmfhDOsiNbcnEON50mFGzW9/w=
This was a non-question, as demonstrated, the hashes are always the same.
The problem in my case was unrelated, the fact that Java uppercases percent encoding on UrlEncoder but .NET doesn't.
Goes to show how important it is to test in isolation!