My XML file:
<?xml version="1.0" encoding="utf-8"?>
<dskh>
<khachhang maso="kh01">
<ten_kh>thehung</ten_kh>
<tuoi_kh>15</tuoi_kh>
<dchi_kh>hochiminh</dchi_kh>
</khachhang>
<khachhang maso="kh02">
<ten_kh>hung</ten_kh>
<tuoi_kh>15</tuoi_kh>
<dchi_kh>hcm</dchi_kh>
</khachhang>
</dskh>
My Encrypt and Decrypt code:
class Program
{
// Call this function to remove the key from memory after use for security.
[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory")]
public static extern bool ZeroMemory(ref string Destination, int Length);
// Function to Generate a 64 bits Key.
static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
DESCryptoServiceProvider desCrypto = (DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Use the Automatically generated key for Encryption.
return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
}
static void EncryptFile(string sInputFilename,
string sOutputFilename,
string sKey) {
FileStream fsInput = new FileStream(sInputFilename,FileMode.Open,FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,FileMode.Create,FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = Encoding.UTF8.GetBytes(sKey);
DES.IV = Encoding.UTF8.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,desencrypt,CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length - 1];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
}
static void DecryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = Encoding.UTF8.GetBytes(sKey);
//Set initialization vector.
DES.IV = Encoding.UTF8.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read);
//Print the contents of the decrypted file.
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
}
static void Main(string[] args)
{
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
// Get the key for the file to encrypt.
sSecretKey = GenerateKey();
// For additional security pin the key.
GCHandle gch = GCHandle.Alloc(sSecretKey, GCHandleType.Pinned);
// Encrypt the file.
EncryptFile(#"C:\xml_kh.xml",
#"C:\xml_encry.xml",
sSecretKey);
//Decrypt the file.
DecryptFile(#"C:\xml_encry.xml",
#"C:\xml_decry.xml",
sSecretKey);
}
}
When i excute Decrypt code, i get Cryptographicexception: Bad Data here:
//Print the contents of the decrypted file.
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
Please help me!!!
Add two lines at the end of EncryptFile function:
cryptostream.Flush();
cryptostream.Close();
EDIT
I missed there is one more error:
byte[] bytearrayinput = new byte[fsInput.Length - 1];
s/b
byte[] bytearrayinput = new byte[fsInput.Length];
Related
Saving base64String as image on FTP Server is saving it as corrupted file.
I am doing following things
converted base64String into byte[].
Initialized MemoryStream with byte converted in above step.
Opened stream from FTP
Write stream on ftp.
Below is the code
public bool WriteFromBase64ToFile(string base64, string path, string fileName)
{
bool result = false;
using (FtpClient ftp = new FtpClient())
{
// setting ftp properties with required values.
ftp.ReadTimeout = 999999999;
ftp.Host = host;
ftp.Credentials = new System.Net.NetworkCredential(username, password);
ftp.Port = Convert.ToInt32(port);
ftp.DataConnectionType = FtpDataConnectionType.AutoPassive;
ftp.Connect();
ftp.ConnectTimeout = 1000000;
// converting base64String into byte array.
byte[] file = Convert.FromBase64String(base64);
if (ftp.IsConnected)
{
int BUFFER_SIZE = file.Length; // 64KB buffer
byte[] buffer = new byte[file.Length];
// Initializing MemoryStream with byte converted from base64String.
MemoryStream ms = new MemoryStream(buffer);
using (Stream readStream = ms)
{
fileName = fileName.ReplacingSpecialCharacterswithEntities();
// Getting stream from ftp and then writing it on FTP server.
using (Stream writeStream = ftp.OpenWrite(path + "/" + fileName+".jpg", FtpDataType.Binary))
{
while (readStream.Position < readStream.Length)
{
buffer.Initialize();
// Reading stream
int bytesRead = readStream.Read(buffer, 0, BUFFER_SIZE);
// Writing stream
writeStream.Write(buffer, 0, bytesRead);
}
// flushing stream.
writeStream.Flush();
}
}
}
}
result = true;
return result;
}
I was wondering what signature algorithm (digestOID) BouncyCastle uses by default if you do not specify it explicitly like like in the code below:
List certList = new ArrayList();
CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
certList.add(signCert);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(signKP.getPrivate());
gen.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
.build(sha1Signer, signCert));
gen.addCertificates(certs);
CMSSignedData sigData = gen.generate(msg, false);
Below is the code example for which I am wondering as you see there is no digestOID(SHA1withRSA) so what type of signature does it use:
import java.io.*;
import java.util.*;
import java.security.*;
import java.security.Security;
import java.security.cert.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.cms.*;
/* Create CMS/pkcs #7 signature using BC provider
M. Gallant 07/02/2003 */
class BCSignFile {
static final boolean DEBUG = false;
public static void main(String args[]) {
System.out.println("");
if (args.length < 4)
usage();
Security.addProvider(new BouncyCastleProvider());
String INFILE = args[0]; // Input file to be signed
String KEYSTORE = args[1]; // Java 2 keystore file
String ALIAS = args[2]; // Java 2 key entry alias
String PSWD = args[3]; // keystore password
// ---- in real implementation, provide some SECURE way to get keystore
// ---- password from user! -------
KeyStore keystore = null;
PublicKey pub = null;
PrivateKey priv = null;
java.security.cert.Certificate storecert = null;
java.security.cert.Certificate[] certChain = null;
ArrayList certList = new ArrayList();
CertStore certs =null;
try{
keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream(KEYSTORE), PSWD.toCharArray());
certChain = keystore.getCertificateChain(ALIAS);
for ( int i = 0; i < certChain.length;i++)
certList.add(certChain[i]);
certs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), "BC");
priv = (PrivateKey)(keystore.getKey(ALIAS, PSWD.toCharArray()));
storecert = keystore.getCertificate(ALIAS);
pub = keystore.getCertificate(ALIAS).getPublicKey();
}
catch(Exception exc){
System.out.println("Problem with keystore access: " + exc.toString()) ;
return;
}
if(DEBUG){
System.out.println("Public Key Format: " + pub.getFormat()) ;
System.out.println("Certificate " + storecert.toString()) ;
}
FileInputStream freader = null;
File f = null;
//------ Get the content data from file -------------
f = new File(INFILE) ;
int sizecontent = ((int) f.length());
byte[] contentbytes = new byte[sizecontent];
try {
freader = new FileInputStream(f);
System.out.println("\nContent Bytes: " + freader.read(contentbytes, 0, sizecontent));
freader.close();
}
catch(IOException ioe) {
System.out.println(ioe.toString());
return;
}
// --- Use Bouncy Castle provider to create CSM/PKCS#7 signed message ---
try{
CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();
signGen.addSigner(priv, (X509Certificate)storecert, CMSSignedDataGenerator.DIGEST_SHA1);
signGen.addCertificatesAndCRLs(certs);
CMSProcessable content = new CMSProcessableByteArray(contentbytes);
CMSSignedData signedData = signGen.generate(content,"BC");
byte[] signeddata = signedData.getEncoded();
System.out.println("Created signed message: " + signeddata.length + " bytes") ;
FileOutputStream envfos = new FileOutputStream("BCsigned.p7s");
envfos.write(signeddata);
envfos.close();
}
catch(Exception ex){
System.out.println("Couldn't generate CMS signed message\n" + ex.toString()) ;
}
}
private static void usage() {
System.out.println("Usage:\n java BCSignFile <contentfile> <keystore> <alias> <keypasswd>") ;
System.exit(1);
}
}
The relevant line is this:
signGen.addSigner(priv, (X509Certificate)storecert, CMSSignedDataGenerator.DIGEST_SHA1);
This line specifies that the digest-algorithm will be SHA-1 and that the signing-algorithm will be decided based on the type of the private key in priv.
If priv contains an RSA key, it will sign using PKCS#1 v.1.5 with SHA-1 ("SHA1withRSA"). You can look in the source of CMSSignedGenerator.getEncOID() to see what happens with other types of private key.
i need to find the public key from certificate as xml string. I can take the public key only as a string with this method:
public string CelesiPublik()
{
X509Certificate cer;
cer = X509Certificate.CreateFromCertFile("C://certificate//EdonBajrami.crt");
string Celesi = cer.GetPublicKeyString();
return Celesi;
}
and then i take this value to the another method. Celesi value now has take celesiPublik
celesiPublik = e.Result;
string NrTelefonit = "044-419-109";
string salt = "VotimiElektronikKosove";
AesManaged aes = new AesManaged();
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(celesiPublik,Encoding.UTF8.GetBytes(salt));
aes.Key = rfc2898.GetBytes(aes.KeySize / 8);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(celesiPublik);
rsa.Encrypt(aes.Key, false);
but it shows me error. How can i resolve this problem?
GregS i cannot use in Windows Phone 7 X509Certificate2. I take my public key with the method:
`X509Certificate cer = new X509Certificate("C://certificate//EdonBajrami.crt");
string publicKey = cer.GetPublicKeyString();`
i can take the public key. Then in another method i take value of the publicKey to another string variable Key:
`string Key = publicKey;
//-----First------
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
//----------
RSAParameters RSAKeyInfo = new RSAParameters();
byte[] celesibyte = System.Text.Encoding.UTF8.GetBytes(celesiPublik);
byte[] Exponent = { 1, 0, 1 };
RSAKeyInfo.Modulus = celesibyte;
RSAKeyInfo.Exponent = Exponent;
rsa.ImportParameters(RSAKeyInfo);
//-----------
/* rsa.FromXmlString(celesi2Publik); */
string edon = "Edon";
byte[] edon1 = Encoding.UTF8.GetBytes(edon);
byte[] edon2 = rsa.Encrypt(edon1, false);'
but it sends me data that is 506 byte, i dont understand why, what is a problem ?
As far as I can tell the X509Certificate class is nearly useless. Perhaps that is why there is a class X509Certificate2? Use the X509Certificate2 class. You can create an RSACryptoServiceProvider directly from the public key like the following:
X509Certificate2 cert = new X509Certificate2(X509Certificate.CreateFromCertFile("C://certificate//EdonBajrami.crt"));
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider) cert.PublicKey.Key;
I have used following code for encryption in Windows Phone:
public static string Encrypt(string dataToEncrypt, string password)
{
AesManaged aes = null;
MemoryStream memoryStream = null;
CryptoStream cryptoStream = null;
string salt = "12345678";
try
{
// Generate a Key based on a Password and HMACSHA1 pseudo-random number generator
// Salt must be at least 8 bytes long
// Use an iteration count of at least 1000
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt), 10000);
// Create AES algorithm
aes = new AesManaged();
// Key derived from byte array with 32 pseudo-random key bytes
aes.Key = rfc2898.GetBytes(32);
// IV derived from byte array with 16 pseudo-random key bytes
aes.IV = rfc2898.GetBytes(16);
// Create Memory and Crypto Streams
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
// Encrypt Data
byte[] data = Encoding.UTF8.GetBytes(dataToEncrypt);
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
// Return Base 64 String
return Convert.ToBase64String(memoryStream.ToArray());
}
finally
{
if (cryptoStream != null)
{
cryptoStream.Close();
}
if (memoryStream != null)
{
memoryStream.Close();
}
if (aes != null)
{
aes.Clear();
}
}
}
public static string Decrypt(string dataToDecrypt, string password)
{
AesManaged aes = null;
MemoryStream memoryStream = null;
string salt = "12345678";
try
{
// Generate a Key based on a Password and HMACSHA1 pseudo-random number generator
// Salt must be at least 8 bytes long
// Use an iteration count of at least 1000
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt), 10000);
// Create AES algorithm
aes = new AesManaged();
// Key derived from byte array with 32 pseudo-random key bytes
aes.Key = rfc2898.GetBytes(32);
// IV derived from byte array with 16 pseudo-random key bytes
aes.IV = rfc2898.GetBytes(16);
// Create Memory and Crypto Streams
memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write);
// Decrypt Data
byte[] data = Convert.FromBase64String(dataToDecrypt);
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
// Return Decrypted String
byte[] decryptBytes = memoryStream.ToArray();
// Dispose
if (cryptoStream != null)
{
cryptoStream.Dispose();
}
// Retval
return Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
}
finally
{
if (memoryStream != null)
{
memoryStream.Dispose();
}
if (aes != null)
{
aes.Clear();
}
}
}
The performance of encyrption is very poor. Can anyone suggest some improvement on above code?
Sure, you could move the key derivation code using Rfc2898DeriveBytes outside of those function since the key for a given password will be constant and will be usually used multiple times. Other than that I don't see much room for improvement.
Perhaps you should introduce some using() brackets to make sure there are no memory leaks. You could have a look at this:
http://zayko.net/post/How-to-EncryptDecrypt-a-String-in-Silverlight-for-Windows-Phone-7.aspx
This would only help if your function became slower over time, instead on the first run.
I have some some time now reshearchd how to encode a password to SHA1 with a salt.
The is the code i used on my web application part, but it will not work on a phone environment.
public class Password
{
private string _password;
private int _salt;
public Password(string strPassword, int nSalt)
{
_password = strPassword;
_salt = nSalt;
}
public string ComputeSaltedHash()
{
// Create Byte array of password string
ASCIIEncoding encoder = new ASCIIEncoding();
Byte[] _secretBytes = encoder.GetBytes(_password);
// Create a new salt
Byte[] _saltBytes = new Byte[4];
_saltBytes[0] = (byte)(_salt >> 24);
_saltBytes[1] = (byte)(_salt >> 16);
_saltBytes[2] = (byte)(_salt >> 8);
_saltBytes[3] = (byte)(_salt);
// append the two arrays
Byte[] toHash = new Byte[_secretBytes.Length + _saltBytes.Length];
Array.Copy(_secretBytes, 0, toHash, 0, _secretBytes.Length);
Array.Copy(_saltBytes, 0, toHash, _secretBytes.Length, _saltBytes.Length);
SHA1 sha1 = SHA1.Create();
Byte[] computedHash = sha1.ComputeHash(toHash);
return encoder.GetString(computedHash);
}
public static int CreateRandomSalt()
{
Byte[] _saltBytes = new Byte[4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(_saltBytes);
return ((((int)_saltBytes[0]) << 24) + (((int)_saltBytes[1]) << 16) +
(((int)_saltBytes[2]) << 8) + ((int)_saltBytes[3]));
}
public static string CreateRandomPassword(int PasswordLength)
{
String _allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ23456789!\"#ยค%&/()=?$+-_.,;'*";
Byte[] randomBytes = new Byte[PasswordLength];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
char[] chars = new char[PasswordLength];
int allowedCharCount = _allowedChars.Length;
for (int i = 0; i < PasswordLength; i++)
{
chars[i] = _allowedChars[(int)randomBytes[i] % allowedCharCount];
}
return new string(chars);
}
}
Silverlight and Windows Phone 7 do not have an ASCIIEncoding. I suggest you use the UTF8Encoding instead. If you are certain that your passwords are always within the ASCII range then this encoding will work the same as the ASCIIEncoding would of had it been present.
If on the other hand you cannot guarantee that passwords are always within the ASCII range then you would need to make sure both ends hash using the UTF8Encoding to ensure generated hashs are the same.