AES Salting iterations, How many required? - encryption

I am trying to execute a simple Encrypt and Decrypt AES and I was trying to use salting. These values will be stored in the DB and retrieved from there. (I cannot use hashing) I am using static key and static salt for the time being.
My question is how many iterations of salting should I do? I mean I have to store the value in the DB and I see that at 2 iterations (128bit key, 42bit salt) I get a encrypted string of 152 charaters for 40 characters. For 4 iterations, it's 364 characters for 40 characters, for 8 iterations 1536 characters for 40 characters and for 16 iterations, a ridiculous 19968 characters for 40 characters.
So what should be my optimal number of iterations?
public static String AESencrypt(String value) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
String valueToEnc = null;
String eValue = value;
for (int i = 0; i < ITERATIONS; i++) {
valueToEnc = salt + eValue;
byte[] encValue = c.doFinal(valueToEnc.getBytes());
eValue = new BASE64Encoder().encode(encValue);
}
return eValue;
}
public static String AESdecrypt(String value) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
String dValue = null;
String valueToDecrypt = value;
for (int i = 0; i < ITERATIONS; i++) {
byte[] decordedValue = new BASE64Decoder().decodeBuffer(valueToDecrypt);
byte[] decValue = c.doFinal(decordedValue);
dValue = new String(decValue).substring(salt.length());
valueToDecrypt = dValue;
}
return dValue;
}

Salting is used on passwords to derive keys. It is not used on ciphertext, not even if it is base 64 encoded. Salting is used to make it harder for an attacker to find the password using brute force or rainbow tables. It is typically used by a PBKDF such as PBKDF2, bcrypt or scrypt.
In your case it doesn't matter how much you encrypt; if the attacker tries the key, decrypts the ciphertext and then finds base 64, the attacker will know he has found the key, and can simply do the number of iterations again.
In general, it does not make sense to encrypt things multiple times; block ciphers themselves already should contain a sufficient number of "rounds".

Related

decrypt AES input on Flutter, when on web use cryptoJS AES

On web, I'm using CryptoJS for decrypto JS:
CryptoJS.AES.decrypt(inputBase64, key).toString(CryptoJS.enc.Utf8);
Example:
input: "tzfwnxVwE/qNoaWRRfqLp11ZyhB4UtKO+0/Lvv5B7eE="
key: "20190225165436_15230006321670000_15510884759030000"
On flutter I can't find any library to decrypt with a key of any length.
I know "For AES, NIST selected three members of the Rijndael family, each with a block size of 128 bits, but three different key lengths: 128, 192 and 256 bits.
"
But I don't know how to convert any length key to 128 bit format?
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:tuple/tuple.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
String encryptAESCryptoJS(String plainText, String passphrase) {
try {
final salt = genRandomWithNonZero(8);
var keyndIV = deriveKeyAndIV(passphrase, salt);
final key = encrypt.Key(keyndIV.item1);
final iv = encrypt.IV(keyndIV.item2);
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final encrypted = encrypter.encrypt(plainText, iv: iv);
Uint8List encryptedBytesWithSalt = Uint8List.fromList(
createUint8ListFromString("Salted__") + salt + encrypted.bytes);
return base64.encode(encryptedBytesWithSalt);
} catch (error) {
throw error;
}
}
String decryptAESCryptoJS(String encrypted, String passphrase) {
try {
Uint8List encryptedBytesWithSalt = base64.decode(encrypted);
Uint8List encryptedBytes =
encryptedBytesWithSalt.sublist(16, encryptedBytesWithSalt.length);
final salt = encryptedBytesWithSalt.sublist(8, 16);
var keyndIV = deriveKeyAndIV(passphrase, salt);
final key = encrypt.Key(keyndIV.item1);
final iv = encrypt.IV(keyndIV.item2);
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final decrypted =
encrypter.decrypt64(base64.encode(encryptedBytes), iv: iv);
return decrypted;
} catch (error) {
throw error;
}
}
Tuple2<Uint8List, Uint8List> deriveKeyAndIV(String passphrase, Uint8List salt) {
var password = createUint8ListFromString(passphrase);
Uint8List concatenatedHashes = Uint8List(0);
Uint8List currentHash = Uint8List(0);
bool enoughBytesForKey = false;
Uint8List preHash = Uint8List(0);
while (!enoughBytesForKey) {
int preHashLength = currentHash.length + password.length + salt.length;
if (currentHash.length > 0)
preHash = Uint8List.fromList(
currentHash + password + salt);
else
preHash = Uint8List.fromList(
password + salt);
currentHash = md5.convert(preHash).bytes;
concatenatedHashes = Uint8List.fromList(concatenatedHashes + currentHash);
if (concatenatedHashes.length >= 48) enoughBytesForKey = true;
}
var keyBtyes = concatenatedHashes.sublist(0, 32);
var ivBtyes = concatenatedHashes.sublist(32, 48);
return new Tuple2(keyBtyes, ivBtyes);
}
Uint8List createUint8ListFromString(String s) {
var ret = new Uint8List(s.length);
for (var i = 0; i < s.length; i++) {
ret[i] = s.codeUnitAt(i);
}
return ret;
}
Uint8List genRandomWithNonZero(int seedLength) {
final random = Random.secure();
const int randomMax = 245;
final Uint8List uint8list = Uint8List(seedLength);
for (int i=0; i < seedLength; i++) {
uint8list[i] = random.nextInt(randomMax)+1;
}
return uint8list;
}
Usage
import 'package:app/utils/cryptojs_aes_encryption_helper.dart';
String plainText = 'PlainText is Me';
var encrypted = encryptAESCryptoJS(plainText, "password");
var decrypted = decryptAESCryptoJS(encrypted, "password");
When you pass CryptoJS a string as the key it treats it as a passphrase and generates the key from it using a key derivation function - in this case PBKDF2. It generates a 256 bit key and a 128 bit initialization vector (IV). It then uses those for the encryption/decryption. You also need to find out what chaining method CryptoJS uses (probably cipher block chaining (CBC)) and what padding method it uses (to make sure that the plain text is a round number of 128 bit blocks - probably PKCS#7).
CryptoJS has this "works out of the box" mode, but it isn't particularly clear what it's doing under the hood - you'd need to read the source code or scour the documentation.
When trying to inter-operate between two systems/languages it's best if you remain in charge of things, rather than letting one end make arbitrary decisions. That way you can make sure that you have the settings the same at each end.
So, you might choose to:
Use PBKDF2 to generate a 128 bit key and 128 bit IV from the string
passphrase - with, say, 9999 rounds
Use PKCS#7 padding
Use AES in CBC mode
The pointycastle package supports all the above in Dart. It looks like CryptoJS supports all of those too.
Start with a passphrase and make sure you can generate the same key and IV in JS and Dart. Then move onto creating the ciphers.
Remember, too, never to encrypt two messages with the same key/IV pair. Use a message sequence number, for example, to slightly change the IV for each message.
Sample encrypt using nodejs script:
var key = CryptoJS.PBKDF2("123456", "123456", {
keySize: 256 / 32
});
var iv = CryptoJS.PBKDF2("123456", "123456", {
keySize: 128 / 32
});
var encrypted = CryptoJS.AES.encrypt('my message', key, { iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
decript using dart
import 'package:encrypt/encrypt.dart' as aes;
import 'package:crypto/crypto.dart';
import 'package:hex/hex.dart';
import 'package:password_hash/pbkdf2.dart';
void main(List<String> arguments) {
String encrypted = 'HbsmGAigiIWmU3MNZAf8+w==';
final generator = PBKDF2(hashAlgorithm: sha1);
final key = aes.Key.fromBase16(HEX.encode(generator.generateKey("123456", "123456", 1, 32)));
final iv = aes.IV.fromBase16(HEX.encode(generator.generateKey("123456", "123456", 1, 16)));
final encrypter = aes.Encrypter(aes.AES(key, mode: aes.AESMode.cbc, padding: 'PKCS7'));
final decrypted = encrypter.decrypt64(encrypted, iv:iv);
print(decrypted);
}

Encryption Failing with error Invalid length for a Base-64 char array or string

I am trying to encrypt a PRIVATE KEY with a passphrase so I can save the file to disk. But the encryption method is throwing the exception: "Invalid length for a Base-64 char array or string".
The Encryption method is (it's a 2048bit key length):
public static string Encrypt(string plainString, string key, int keySize = Keysize.SymmetricKeyLength)
{
var aesEncryption = new RijndaelManaged
{
KeySize = keySize,
BlockSize = 128,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
IV = Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String(key)).Split(',')[0]),
Key = Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String(key)).Split(',')[1])
};
byte[] plainText = Encoding.UTF8.GetBytes(plainString);
ICryptoTransform crypto = aesEncryption.CreateEncryptor();
// The result of the encryption and decryption
byte[] cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length);
return Convert.ToBase64String(cipherText);
}
I am converting the Private Key to a Base64 string before passing it down to the encryption method using this method:
public string EncodeTo64(string plainString)
{
var bytes = Encoding.UTF8.GetBytes(plainString);
return Convert.ToBase64String(bytes);
}
The Private Key is:
<RSAKeyValue><Modulus>rhtMjLTg17sYlns4ktTow9eeuwRNra0+AO2HqESGmA8zkxe/uOv0msXzzLWUWzdPaTxi4OV+PNVPBAHW1C0CTT/33NlvipkJ1Qr5BJK1TiVZCMInshe4OL/7GNnPUPhsS6DZ/c/fnWLoxtRMUmkKgpWmtXGs7ZSoIztdJ1bgiygJWCDvrHTokVIzDaNzRonZIFk41Qt4rPofCEawjkR639OcOfazNlmU9JjvRs3ysoYghDzvVuLvJvPK7zCMzpJMQFQE7cipezXbumTqSdp20mQXJduDbD9qLKXOvcTw+2KPoNlUp+IRQrOmSf+Dl4Vxi+8+UuOH7KDLz7yL9IOPeQ==</Modulus><Exponent>AQAB</Exponent><P>2AHey3Tgg/K8M16kv6bWk1BsFGhg9xXZw2ruVhS620gyvPBtWBuOU+tzPRnEplw+Kp9jua7Nu4JkKwpQdZvRqeW42d/UCergkdNRheM3DXYj/xQNs8a1diTNe72elCsCfSHr1z/vgN+Cp+v8O4BzX07TrHeGOOP/7HWhE6setxM=</P><Q>zld05TyC/vVI2sBgaR/iYyXdUO3iIIwkGSyOmfDr1dbCKFR7btGLEsW9EpCGibyGPbAk4jA9BLU1bviBM8iH6mxWn1s4UAiIha0QSM2K9NWUPi67FELl6Fs2eLHl9qRniBhAOBCGArklail+YadKCtUsrWhfJgvO3uxkp+fg9MM=</Q><DP>sziaCmVnAxObY2PbfciHsKLBig0wptHSZHmMVo/MmbRFpM43aysx5B8u9jszFnTif6rPq3iF6lY9lhhwuaQXScf4n40++RuQSG307gmf2+Nx6mpRFCCC3wuaElk6AeXNotVKQMYjieHpHjqGhTgGgcV9i1OAYiOKbD8M7qzER1E=</DP><DQ>FEazzfLsTHF9/0D4OFxRurx1ywYVOm2K/o5KVQY/pnu8CIqEtpcQu3+C3Ngm4FIOPvGYLkHfPR8xaP4ydAw4juimenJUTkkIYVpoRz8rcHOsZY/iAlOwk+yipamVl28AXXdEmD3HbW0UKCJ7sMznkbjw8vlWoD54zZ8dJQK8MFE=</DQ><InverseQ>FUFC9v5B1mXxbbiD4WZm/KGIa3XO5+K9FwSRroj8wNMt+JY5aMS8SfUcrZMvUXfHS9+3BYXBIlxPBUm6HnfB7yPE9S0LFzRpB7APbJ0HVIlSjMS9ZdkqxShGAEufYx/FKQXomJlEXXkpgAiDnUnCR2H+ekQf1YpQUzol2KedwfA=</InverseQ><D>gEhc/s/HWyzf0QC5jnaRirs0mVdyZKVhKg3aBoF3KlMJDThSa05vzBpOqGaiCROXz1JPCKYPfYMt1SYFxA/lwkV/u5n6NYTNWcvb7yKptAqQr4Ne/Dm94xKRUJ4rwt1H7fF2rSyc9roKCXYjRhVfSRg63TYE1IjT2iHDYVkB2YVPK67O2O7YmQXeUHMRMVwXpnZCvweleRKlYbVFx2N7ZEC1TZoUn2RKsiBEem1eNSwnLa4wUf1Xl8Q8h+ziY0GnREf9JpTZhJW7f4MKsqLyOMgmoskKiIOWlnwq/b01ivB2CXFhxiiVuNUPPiMuJu6bhljeulvKl32kEzLAFxm2gQ==</D></RSAKeyValue>
and the resulting Base64 string from the above conversion method is:
PFJTQUtleVZhbHVlPjxNb2R1bHVzPnJodE1qTFRnMTdzWWxuczRrdFRvdzllZXV3Uk5yYTArQU8ySHFFU0dtQTh6a3hlL3VPdjBtc1h6ekxXVVd6ZFBhVHhpNE9WK1BOVlBCQUhXMUMwQ1RULzMzTmx2aXBrSjFRcjVCSksxVGlWWkNNSW5zaGU0T0wvN0dOblBVUGhzUzZEWi9jL2ZuV0xveHRSTVVta0tncFdtdFhHczdaU29JenRkSjFiZ2l5Z0pXQ0R2ckhUb2tWSXpEYU56Um9uWklGazQxUXQ0clBvZkNFYXdqa1I2MzlPY09mYXpObG1VOUpqdlJzM3lzb1lnaER6dlZ1THZKdlBLN3pDTXpwSk1RRlFFN2NpcGV6WGJ1bVRxU2RwMjBtUVhKZHVEYkQ5cUxLWE92Y1R3KzJLUG9ObFVwK0lSUXJPbVNmK0RsNFZ4aSs4K1V1T0g3S0RMejd5TDlJT1BlUT09PC9Nb2R1bHVzPjxFeHBvbmVudD5BUUFCPC9FeHBvbmVudD48UD4yQUhleTNUZ2cvSzhNMTZrdjZiV2sxQnNGR2hnOXhYWncycnVWaFM2MjBneXZQQnRXQnVPVSt0elBSbkVwbHcrS3A5anVhN051NEprS3dwUWRadlJxZVc0MmQvVUNlcmdrZE5SaGVNM0RYWWoveFFOczhhMWRpVE5lNzJlbENzQ2ZTSHIxei92Z04rQ3ArdjhPNEJ6WDA3VHJIZUdPT1AvN0hXaEU2c2V0eE09PC9QPjxRPnpsZDA1VHlDL3ZWSTJzQmdhUi9pWXlYZFVPM2lJSXdrR1N5T21mRHIxZGJDS0ZSN2J0R0xFc1c5RXBDR2lieUdQYkFrNGpBOUJMVTFidmlCTThpSDZteFduMXM0VUFpSWhhMFFTTTJLOU5XVVBpNjdGRUxsNkZzMmVMSGw5cVJuaUJoQU9CQ0dBcmtsYWlsK1lhZEtDdFVzcldoZkpndk8zdXhrcCtmZzlNTT08L1E+PERQPnN6aWFDbVZuQXhPYlkyUGJmY2lIc0tMQmlnMHdwdEhTWkhtTVZvL01tYlJGcE00M2F5c3g1Qjh1OWpzekZuVGlmNnJQcTNpRjZsWTlsaGh3dWFRWFNjZjRuNDArK1J1UVNHMzA3Z21mMitOeDZtcFJGQ0NDM3d1YUVsazZBZVhOb3RWS1FNWWppZUhwSGpxR2hUZ0dnY1Y5aTFPQVlpT0tiRDhNN3F6RVIxRT08L0RQPjxEUT5GRWF6emZMc1RIRjkvMEQ0T0Z4UnVyeDF5d1lWT20ySy9vNUtWUVkvcG51OENJcUV0cGNRdTMrQzNOZ200RklPUHZHWUxrSGZQUjh4YVA0eWRBdzRqdWltZW5KVVRra0lZVnBvUno4cmNIT3NaWS9pQWxPd2sreWlwYW1WbDI4QVhYZEVtRDNIYlcwVUtDSjdzTXpua2Jqdzh2bFdvRDU0elo4ZEpRSzhNRkU9PC9EUT48SW52ZXJzZVE+RlVGQzl2NUIxbVh4YmJpRDRXWm0vS0dJYTNYTzUrSzlGd1NScm9qOHdOTXQrSlk1YU1TOFNmVWNyWk12VVhmSFM5KzNCWVhCSWx4UEJVbTZIbmZCN3lQRTlTMExGelJwQjdBUGJKMEhWSWxTak1TOVpka3F4U2hHQUV1Zll4L0ZLUVhvbUpsRVhYa3BnQWlEblVuQ1IySCtla1FmMVlwUVV6b2wyS2Vkd2ZBPTwvSW52ZXJzZVE+PEQ+Z0VoYy9zL0hXeXpmMFFDNWpuYVJpcnMwbVZkeVpLVmhLZzNhQm9GM0tsTUpEVGhTYTA1dnpCcE9xR2FpQ1JPWHoxSlBDS1lQZllNdDFTWUZ4QS9sd2tWL3U1bjZOWVROV2N2Yjd5S3B0QXFRcjROZS9EbTk0eEtSVUo0cnd0MUg3ZkYyclN5Yzlyb0tDWFlqUmhWZlNSZzYzVFlFMUlqVDJpSERZVmtCMllWUEs2N08yTzdZbVFYZVVITVJNVndYcG5aQ3Z3ZWxlUktsWWJWRngyTjdaRUMxVFpvVW4yUktzaUJFZW0xZU5Td25MYTR3VWYxWGw4UThoK3ppWTBHblJFZjlKcFRaaEpXN2Y0TUtzcUx5T01nbW9za0tpSU9XbG53cS9iMDFpdkIyQ1hGaHhpaVZ1TlVQUGlNdUp1NmJobGpldWx2S2wzMmtFekxBRnhtMmdRPT08L0Q+PC9SU0FLZXlWYWx1ZT4=
Apparently this Base64 string is invalid and the encryption fails.
Can anybody see where I am going wrong?
Your Base64 string appears to be valid. When I decode it I get some recognisable XML for RSA:
<RSAKeyValue>
<Modulus>rht ... PeQ==</Modulus>
<Exponent>AQAB</Exponent>
<P>2AH ... txM=</P>
<Q>zld ... 9MM=</Q>
<DP>szi ... R1E=</DP>
<DQ>FEa ... 8MFE=</DQ>
<InverseQ>FUF ... wfA=</InverseQ>
<D>gEh ... m2gQ==</D>
</RSAKeyValue>
That has added newlines and is abbreviated for clarity.
Was that what you were expecting? If it was then I suggest that you check each of the included pieces of Base64 for errors. Alternatively, it may just be that your initial piece of Base64 is too long.
Fixed! It appears the error was a little misleading (or likely I was being stupid!) and it looks like it was NOT the plain text for encryption that was the cause of the exception but the password/passphrase.
I found another app I was using this method in and found the KEY was the problem. I was passing a plain text password in initially, then I changed this to a SHA-256 hash of the password when this was in fact not a valid key.
I added these two methods (the later of which I found on here):
public static string AesKeyFromPassword(string password, int keySize = Keysize.SymmetricKeyLength)
{
byte[] passwordByteArray = CreateKey(password);
var aesEncryption = new RijndaelManaged
{
KeySize = keySize,
BlockSize = 128,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = passwordByteArray
};
aesEncryption.GenerateIV();
string ivStr = Convert.ToBase64String(aesEncryption.IV);
string keyStr = Convert.ToBase64String(aesEncryption.Key);
string completeKey = ivStr + "," + keyStr;
return Convert.ToBase64String(Encoding.UTF8.GetBytes(completeKey));
}
private static byte[] CreateKey(string password)
{
var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };
const int Iterations = 9872;
using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
return rfc2898DeriveBytes.GetBytes(32);
}
This now takes the plain text password/phrase and generates a valid encryption key which I then use in the Encrypt method.
Thank for your help guys! I can now securely store the Private Key! :)

How to generate a document ID or Report ID of 8 characters in .net

Can someone point me to the preferred method for generating a report or document ID? I have been looking at maybe using a guid that would be reduced down to a shorter length. We have an application that creates an ID for reports that is about 8 characters long. They appear to be using some type of hash code. Probably using a base 36 encoding scheme. But I cant seem to find a way to make the hash code come out to a length of 8 characters since people have to use them to refer to the documents. They would also be used in a disconnected environment, so you couldnt look up the next usable serialized number in the chain. Just wondering what some of you use in applications like this?
The .net Framwork provides RNGCryptoServiceProvider class which Implements a cryptographic Random Number Generator (RNG) using the implementation provided by the cryptographic service provider (CSP). This class is usually used to generate random numbers. Although I can use this class to generate unique number in some sense but it is also not collision less. Moreover while generating key we can make key more complicated by making it as alpha numeric rather than numeric only. So, I used this class along with some character masking to generate unique key of fixed length.
private string GetUniqueKey()
{
int maxSize = 8 ;
int minSize = 5 ;
char[] chars = new char[62];
string a;
a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
chars = a.ToCharArray();
int size = maxSize ;
byte[] data = new byte[1];
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
crypto.GetNonZeroBytes(data) ;
size = maxSize ;
data = new byte[size];
crypto.GetNonZeroBytes(data);
StringBuilder result = new StringBuilder(size) ;
foreach(byte b in data )
{ result.Append(chars[__b % (chars.Length - )>); }
<span class="code-keyword">return result.ToString();
}
http://www.codeproject.com/Articles/14403/Generating-Unique-Keys-in-Net
This is what I ended up using. It is a base36 encoding. I borrowed parts of the code from other people, so I cant claim that I wrote it all, but I hope this helps others. This will produce about a 12 digit record ID, or unique ID for databases etc. It uses only the last 2 digits of the year, so it should be good for 100 years.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Base36Converter
{
public partial class Form1 : Form
{
private const string CharList = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public Form1()
{
InitializeComponent();
}
//Base 36 number consists of only numbers and uppercase letters only.
private void button1_Click(object sender, EventArgs e)
{
if (textBox2.Text.Length > 0)
{
label3.Text = "";
//Get Date and Time Stamp
string temp1 = GetTimestamp(DateTime.Now);
//Turn it into a long number
long l = Convert.ToInt64(temp1);
//Now encode it as a base36 number.
string s1 = Encode(l);
//Get userID as a number, i.e. 1055 (User's index number) and create as a long type.
long l1 = Convert.ToInt64(textBox2.Text);
//Encode it as a base36 number.
string s2 = Encode(l1);
//Now display it as the encoded user number + datetime encoded number (Concatenated)
textBox1.Text = s2 + s1;
}
else
{
label3.Text = "User Number must be greater than 0. ie 1055";
}
}
public static String Encode(long input)
{
if (input < 0) throw new ArgumentOutOfRangeException("input", input, "input cannot be negative");
char[] clistarr = CharList.ToCharArray();
var result = new Stack<char>();
while (input != 0)
{
result.Push(clistarr[input % 36]);
input /= 36;
}
return new string(result.ToArray());
}
public static String GetTimestamp(DateTime value)
{
return value.ToString("yyMMddHHmmssffff");
}
private void Form1_Load(object sender, EventArgs e)
{
label3.Text = "";
}
}
}

How to generate random unique 16 digit number in asp.net without collision

how can i generate 16 digit unique random numbers without any repetition in c# asp.net, as i have read the concept of GUID which generate characters along with numbers but i don't want characters
kindly suggest is there any way to acheive it
You can create a random number using the Random class:
private static Random RNG = new Random();
public string Create16DigitString()
{
var builder = new StringBuilder();
while (builder.Length < 16)
{
builder.Append(RNG.Next(10).ToString());
}
return builder.ToString();
}
Ensuring that there are no collisions requires you to track all results that you have previously returned, which is in effect a memory leak (NB I do not recommend that you use this - keeping track of all previous results is a bad idea, rely on the entropy of a random string of up to 16 characters, if you want more uniqueness, increase the entropy, but I shall include it to show how it could be done):
private static HashSet<string> Results = new HashSet<string>();
public string CreateUnique16DigitString()
{
var result = Create16DigitString();
while (!Results.Add(result))
{
result = Create16DigitString();
}
return result;
}

AES in ASP.NET with VB.NET

What is a good link or article on encrypting a URL link with AES to pass username to another web site in ASP.NET using VB.NET 2005?
FYI: The receiving web site will have access to the private KEY to decrypt.
First
Don't do it! Writing your own crypto system can easily lead to making mistakes. It's best to use an existing system, or if not, get someone who knows cryptography to do it. If you have to do it yourself, read Practical Cryptography.
And please, remember: "We already have enough fast, insecure systems." (Bruce Schneier) -- Do things correct and worry about performance later.
That said, if you are stuck on using AES to roll your own, here are a few pointers.
Initialization Vector
AES is a block cipher. Given a key and a block of plaintext, it converts it to a specific ciphertext. The problem with this is that the same blocks of data will generate the same ciphertext with the same key, every time. So suppose you send data like this:
user=Encrypt(Username)&roles=Encrypt(UserRoles)
They're two separate blocks, and the UserRoles encryption will have the same ciphertext each time, regardless of the name. All I need is the ciphertext for an admin, and I can drop it right in with my cipher'd username. Oops.
So, there are cipher operation modes. The main idea is that you'll take the ciphertext of one block, and XOR it into the ciphertext of the next block. That way we'll do Encrypt(UserRoles, Username), and the Username ciphertext is affected by the UserRoles.
The problem is that the first block is still vulnerable - just by seeing someone's ciphertext, I might know their roles. Enter the initialization vector. The IV "starts up" the cipher and ensures it has random data to encrypt the rest of the stream. So now the UserRoles ciphertext has the ciphertext of the random IV XOR'd in. Problem solved.
So, make sure you generate a random IV for each message. The IV is not sensitive and can be sent plaintext with the ciphertext. Use an IV large enough -- the size of the block should be fine for many cases.
Integrity
AES doesn't provide integrity features. Anyone can modify your ciphertext, and the decrypt will still work. It's unlikely it'll be valid data in general, but it might be hard to know what valid data is. For instance, if you're transmitting a GUID encrypted, it'd be easy to modify some bits and generate a completely different one. That could lead to application errors and so on.
The fix there is to run a hash algorithm (use SHA256 or SHA512) on the plaintext, and include that in the data you transmit. So if my message is (UserName, Roles), you'll send (UserName, Roles, Hash(UserName, Roles)). Now if someone tampers with the ciphertext by flipping a bit, the hash will no longer compute and you can reject the message.
Key derivation
If you need to generate a key from a password, use the built-in class: System.Security.Cryptography.PasswordDeriveBytes. This provides salting and iterations, which can improve the strength of derived keys and reduce the chance of discovering the password if the key is compromised.
Timing/replay
Edit: Sorry for not mentioning this earlier :P. You also need to make sure you have an anti-replay system. If you simply encrypt the message and pass it around, anyone who gets the message can just resend it. To avoid this, you should add a timestamp to the message. If the timestamp is different by a certain threshold, reject the message. You may also want to include a one-time ID with it (this could be the IV) and reject time-valid messages that come from other IPs using the same ID.
It's important to make sure you do the hash verification when you include the timing information. Otherwise, someone could tamper with a bit of the ciphertext and potentially generate a valid timestamp if you don't detect such brute force attempts.
Sample code
Since apparently using an IV correctly is controversial for some folks, here's some code that'll generate random IVs and add them to your output for you. It'll also perform the authentication step, making sure the encrypted data wasn't modified.
using System;
using System.Security.Cryptography;
using System.Text;
class AesDemo {
const int HASH_SIZE = 32; //SHA256
/// <summary>Performs encryption with random IV (prepended to output), and includes hash of plaintext for verification.</summary>
public static byte[] Encrypt(string password, byte[] passwordSalt, byte[] plainText) {
// Construct message with hash
var msg = new byte[HASH_SIZE + plainText.Length];
var hash = computeHash(plainText, 0, plainText.Length);
Buffer.BlockCopy(hash, 0, msg, 0, HASH_SIZE);
Buffer.BlockCopy(plainText, 0, msg, HASH_SIZE, plainText.Length);
// Encrypt
using (var aes = createAes(password, passwordSalt)) {
aes.GenerateIV();
using (var enc = aes.CreateEncryptor()) {
var encBytes = enc.TransformFinalBlock(msg, 0, msg.Length);
// Prepend IV to result
var res = new byte[aes.IV.Length + encBytes.Length];
Buffer.BlockCopy(aes.IV, 0, res, 0, aes.IV.Length);
Buffer.BlockCopy(encBytes, 0, res, aes.IV.Length, encBytes.Length);
return res;
}
}
}
public static byte[] Decrypt(string password, byte[] passwordSalt, byte[] cipherText) {
using (var aes = createAes(password, passwordSalt)) {
var iv = new byte[aes.IV.Length];
Buffer.BlockCopy(cipherText, 0, iv, 0, iv.Length);
aes.IV = iv; // Probably could copy right to the byte array, but that's not guaranteed
using (var dec = aes.CreateDecryptor()) {
var decBytes = dec.TransformFinalBlock(cipherText, iv.Length, cipherText.Length - iv.Length);
// Verify hash
var hash = computeHash(decBytes, HASH_SIZE, decBytes.Length - HASH_SIZE);
var existingHash = new byte[HASH_SIZE];
Buffer.BlockCopy(decBytes, 0, existingHash, 0, HASH_SIZE);
if (!compareBytes(existingHash, hash)){
throw new CryptographicException("Message hash incorrect.");
}
// Hash is valid, we're done
var res = new byte[decBytes.Length - HASH_SIZE];
Buffer.BlockCopy(decBytes, HASH_SIZE, res, 0, res.Length);
return res;
}
}
}
static bool compareBytes(byte[] a1, byte[] a2) {
if (a1.Length != a2.Length) return false;
for (int i = 0; i < a1.Length; i++) {
if (a1[i] != a2[i]) return false;
}
return true;
}
static Aes createAes(string password, byte[] salt) {
// Salt may not be needed if password is safe
if (password.Length < 8) throw new ArgumentException("Password must be at least 8 characters.", "password");
if (salt.Length < 8) throw new ArgumentException("Salt must be at least 8 bytes.", "salt");
var pdb = new PasswordDeriveBytes(password, salt, "SHA512", 129);
var key = pdb.GetBytes(16);
var aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Key = pdb.GetBytes(aes.KeySize / 8);
return aes;
}
static byte[] computeHash(byte[] data, int offset, int count) {
using (var sha = SHA256.Create()) {
return sha.ComputeHash(data, offset, count);
}
}
public static void Main() {
var password = "1234567890!";
var salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
var ct1 = Encrypt(password, salt, Encoding.UTF8.GetBytes("Alice; Bob; Eve;: PerformAct1"));
Console.WriteLine(Convert.ToBase64String(ct1));
var ct2 = Encrypt(password, salt, Encoding.UTF8.GetBytes("Alice; Bob; Eve;: PerformAct2"));
Console.WriteLine(Convert.ToBase64String(ct2));
var pt1 = Decrypt(password, salt, ct1);
Console.WriteLine(Encoding.UTF8.GetString(pt1));
var pt2 = Decrypt(password, salt, ct2);
Console.WriteLine(Encoding.UTF8.GetString(pt2));
// Now check tampering
try {
ct1[30]++;
Decrypt(password, salt, ct1);
Console.WriteLine("Error: tamper detection failed.");
} catch (Exception ex) {
Console.WriteLine("Success: tampering detected.");
Console.WriteLine(ex.ToString());
}
}
}
Output:
JZVaD327sDmCmdzY0PsysnRgHbbC3eHb7YXALb0qxFVlr7Lkj8WaOZWc1ayWCvfhTUz/y0QMz+uv0PwmuG8VBVEQThaNTD02JlhIs1DjJtg=
QQvDujNJ31qTu/foDFUiVMeWTU0jKL/UJJfFAvmFtz361o3KSUlk/zH+4701mlFEU4Ce6VuAAuaiP1EENBJ74Wc8mE/QTofkUMHoa65/5e4=
Alice; Bob; Eve;: PerformAct1 Alice;
Bob; Eve;: PerformAct2 Success:
tampering detected.
System.Security.Cryptography.CryptographicException:
Message hash incorrect. at
AesDemo.Decrypt(String password,
Byte[] passwordSalt, Byte[]
cipherText) in
C:\Program.cs:line
46 at AesDemo.Main() in
C:\Program.cs:line
100
After removing the random IV and the hash, here's the type of output:
tZfHJSFTXYX8V38AqEfYVXU5Dl/meUVAond70yIKGHY=
tZfHJSFTXYX8V38AqEfYVcf9a3U8vIEk1LuqGEyRZXM=
Notice how the first block, corresponding to "Alice; Bob; Eve;" is the same. "Corner case" indeed.
Example without hashing
Here's a simple example of passing a 64-bit integer. Just encrypt and you're open to attack. In fact, the attack is easily done, even with CBC padding.
public static void Main() {
var buff = new byte[8];
new Random().NextBytes(buff);
var v = BitConverter.ToUInt64(buff, 0);
Console.WriteLine("Value: " + v.ToString());
Console.WriteLine("Value (bytes): " + BitConverter.ToString(BitConverter.GetBytes(v)));
var aes = Aes.Create();
aes.GenerateIV();
aes.GenerateKey();
var encBytes = aes.CreateEncryptor().TransformFinalBlock(BitConverter.GetBytes(v), 0, 8);
Console.WriteLine("Encrypted: " + BitConverter.ToString(encBytes));
var dec = aes.CreateDecryptor();
Console.WriteLine("Decrypted: " + BitConverter.ToUInt64(dec.TransformFinalBlock(encBytes, 0, encBytes.Length), 0));
for (int i = 0; i < 8; i++) {
for (int x = 0; x < 250; x++) {
encBytes[i]++;
try {
Console.WriteLine("Attacked: " + BitConverter.ToUInt64(dec.TransformFinalBlock(encBytes, 0, encBytes.Length), 0));
return;
} catch { }
}
}
}
Output:
Value: 6598637501946607785 Value
(bytes): A9-38-19-D1-D8-11-93-5B
Encrypted:
31-59-B0-25-FD-C5-13-D7-81-D8-F5-8A-33-2A-57-DD
Decrypted: 6598637501946607785
Attacked: 14174658352338201502
So, if that's the kind of ID you're sending, it could quite easily be changed to another value. You need to authenticate outside of your message. Sometimes, the message structure is unlikely to fall into place and can sorta act as a safeguard, but why rely on something that could possibly change? You need to be able to rely on your crypto working correctly regardless of the application.
I wrote a blog post which has a sample project that you can download here (C# though):
http://www.codestrider.com/blog/read/AESFileEncryptorWithRSAEncryptedKeys.aspx
The code basically uses AES for encryption of binary data and then RSA encrypts the Key and the IV using an X509Certificate. So, as long as the private key certificate is available, the Key and IV can be decrypted, and then in turn the AES encrypted data can be decrypted ..
You could set up your certificate stores so that the 'encryptor' only has access to the public key certificate, while the 'decryptor' has access to the private key.
This allows you to encrypt using different Key and IV each time and avoid hardcoding anything.. which I believe is more secure. There should be nothing in your source code that would easily allow someone to decrypt your data - and if your system was ever compromised, you would only need to swap out the certificates with new ones. No need to recompile the application with new hardcoded values.. :)
The sample code may be slightly different from your intended use, but I think the technique and some of the code might be useful to you.
Below you'll find a class that provides AES Encryption/Decryption methods that explicitly provide URL-friendly strings for use in applications like yours. It also has the methods that work with byte arrays.
NOTE: you should use different values in the Key and Vector arrays! You wouldn't want someone to figure out your keys by just assuming that you used this code as-is! All you have to do is change some of the numbers (must be <= 255) in the Key and Vector arrays.
Using it is easy: just instantiate the class and then call (usually) EncryptToString(string StringToEncrypt) and DecryptString(string StringToDecrypt) as methods. It couldn't be any easier (or more secure) once you have this class in place.
using System;
using System.Data;
using System.Security.Cryptography;
using System.IO;
public class SimpleAES
{
// Change these keys
private byte[] Key = { 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 };
private byte[] Vector = { 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 2521, 112, 79, 32, 114, 156 };
private ICryptoTransform EncryptorTransform, DecryptorTransform;
private System.Text.UTF8Encoding UTFEncoder;
public SimpleAES()
{
//This is our encryption method
RijndaelManaged rm = new RijndaelManaged();
//Create an encryptor and a decryptor using our encryption method, key, and vector.
EncryptorTransform = rm.CreateEncryptor(this.Key, this.Vector);
DecryptorTransform = rm.CreateDecryptor(this.Key, this.Vector);
//Used to translate bytes to text and vice versa
UTFEncoder = new System.Text.UTF8Encoding();
}
/// -------------- Two Utility Methods (not used but may be useful) -----------
/// Generates an encryption key.
static public byte[] GenerateEncryptionKey()
{
//Generate a Key.
RijndaelManaged rm = new RijndaelManaged();
rm.GenerateKey();
return rm.Key;
}
/// Generates a unique encryption vector
static public byte[] GenerateEncryptionVector()
{
//Generate a Vector
RijndaelManaged rm = new RijndaelManaged();
rm.GenerateIV();
return rm.IV;
}
/// ----------- The commonly used methods ------------------------------
/// Encrypt some text and return a string suitable for passing in a URL.
public string EncryptToString(string TextValue)
{
return ByteArrToString(Encrypt(TextValue));
}
/// Encrypt some text and return an encrypted byte array.
public byte[] Encrypt(string TextValue)
{
//Translates our text value into a byte array.
Byte[] bytes = UTFEncoder.GetBytes(TextValue);
//Used to stream the data in and out of the CryptoStream.
MemoryStream memoryStream = new MemoryStream();
/*
* We will have to write the unencrypted bytes to the stream,
* then read the encrypted result back from the stream.
*/
#region Write the decrypted value to the encryption stream
CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write);
cs.Write(bytes, 0, bytes.Length);
cs.FlushFinalBlock();
#endregion
#region Read encrypted value back out of the stream
memoryStream.Position = 0;
byte[] encrypted = new byte[memoryStream.Length];
memoryStream.Read(encrypted, 0, encrypted.Length);
#endregion
//Clean up.
cs.Close();
memoryStream.Close();
return encrypted;
}
/// The other side: Decryption methods
public string DecryptString(string EncryptedString)
{
return Decrypt(StrToByteArray(EncryptedString));
}
/// Decryption when working with byte arrays.
public string Decrypt(byte[] EncryptedValue)
{
#region Write the encrypted value to the decryption stream
MemoryStream encryptedStream = new MemoryStream();
CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write);
decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length);
decryptStream.FlushFinalBlock();
#endregion
#region Read the decrypted value from the stream.
encryptedStream.Position = 0;
Byte[] decryptedBytes = new Byte[encryptedStream.Length];
encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length);
encryptedStream.Close();
#endregion
return UTFEncoder.GetString(decryptedBytes);
}
/// Convert a string to a byte array. NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so).
// System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
// return encoding.GetBytes(str);
// However, this results in character values that cannot be passed in a URL. So, instead, I just
// lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100).
public byte[] StrToByteArray(string str)
{
if (str.Length == 0)
throw new Exception("Invalid string value in StrToByteArray");
byte val;
byte[] byteArr = new byte[str.Length / 3];
int i = 0;
int j = 0;
do
{
val = byte.Parse(str.Substring(i, 3));
byteArr[j++] = val;
i += 3;
}
while (i < str.Length);
return byteArr;
}
// Same comment as above. Normally the conversion would use an ASCII encoding in the other direction:
// System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
// return enc.GetString(byteArr);
public string ByteArrToString(byte[] byteArr)
{
byte val;
string tempStr = "";
for (int i = 0; i <= byteArr.GetUpperBound(0); i++)
{
val = byteArr[i];
if (val < (byte)10)
tempStr += "00" + val.ToString();
else if (val < (byte)100)
tempStr += "0" + val.ToString();
else
tempStr += val.ToString();
}
return tempStr;
}
}
Markt pointed out that Rijndael uses the AES encryption algorithm. Since a managed implementation ships with the .net framework (and has since at least 1.1), using it should satisfy the OP.
The API docs have a pretty straightforward example of using Rijndael as an encryption and decryption stream.
If you've got a way to get the shared secret (e.g., the private key) to the other website then you might be able to get away with using plain old symmetric encryption (no public key, both sides know the IV and private key). This is especially the case if your brain is the "insecure channel" across which the key is shared (e.g., you administer both websites). :)
Have a look at "Keep Your Data Secure
with the New Advanced Encryption
Standard". An AES implementation
doesn't ship with the .NET framework
but it links to a custom
implementation (AES.exe).
1:
http://msdn.microsoft.com/en-us/magazine/cc164055.aspx

Resources