I'm a complete beginner to any sort of decrypting. I wrote a class that I think should be quite secure. Can you give me constructive criticism of how could I improve the algorithm.
package main;
import java.util.Random;
public class Main {
public static void main(String[] args) {
//we will be playing around with this string
new Main("1234567890abc");
}
private Random rnd;
private byte[] randoms;
/**
* Starts up RNG
* Prints out a test
*/
public Main(String password) {
//random long generated from the password
long randomLong = randomNumber(password);
//Random class using randomLong as seed
rnd = new Random(randomLong);
randoms = new byte[password.length()];
//Array of random bytes generated with rnd
rnd.nextBytes(randoms);
System.out.println(randomNumber(password));
String cryped = encrypt(password);
String decryped = decrypt(cryped);
System.out.println(cryped);
System.out.println(decryped);
}
/**
* Encrypts the password.
*/
private String encrypt(String password) {
char[] chars = password.toCharArray();
for (int i = 0; i < chars.length; i++) {
chars[i] = (char) (chars[i] + randoms[i]);
}
return String.valueOf(chars);
}
/**
* Decrypts an allready encryped password.
*/
private String decrypt(String crypted) {
char[] chars = crypted.toCharArray();
for (int i = 0; i < chars.length; i++) {
chars[i] = (char) (chars[i] - randoms[i]);
}
return String.valueOf(chars);
}
/**
* Finds a random number BASED ON PASSWORD
*/
private long randomNumber(String password)
{
char[] chars = password.toCharArray();
long number = 0;
for (char c : chars) {
number += c;
}
number *= chars.length;
return number;
}
}
The class is written in Java but should be readable to anyone.
Don't reinvent your own cryptography in real life (is this an excercise?) Even experts make mistakes. Use something that's been publically scrutinized.
The java random number generator is not cryptographically secure. With a long enough text to encrypt, patterns will emerge that can permit various information leaks upto and including revealing the password (but see point three) and the plaintext.
You use the password to seed the random number generator. This is a standard (and fine) idea, but you do so using an algorithm that is invariant to permutation! i.e. Your encryption treats "sinecure" and "insecure" or other passwords that are anagrams as equivalent (and probably others too). For a strong password of up to 16 letters and no codepoints beyond 255, the highest reachable seed is 255*16*16 = 65280; but there are even fewer possibilities since there are seeds lower than this which are not reachable. On my keyboard, bruteforcing shows just 9734 different seeds for passwords consisting solely of keyboard-writable characters excluding newline (I count 95) of up to 16 characters in length; that's less than 1 bit of entropy per letter.
CodeInChaos has a few additional observations in his answer: you're using a stream cipher (even harder to get right!). You're also encrypting the password which suggests you may be looking for a hash not an encryption function, (or is that just an example?).
By the way if you're trying to store passwords; don't - not even encrypted! See the sony fiasco for why; you may get hacked, you may lose your password database, and your encryption keys may be known to the attacker. Instead, use standard, best-practice password hashing (and prefer a standard preexisting component if possible). Such a system should at least use a secure hash such as sha1 or better; passwords should be individually salted (the salt can be stored plaintext), and the process should be made computationally expensive to make brute-force unattractive. See http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html for details.
Horribly broken in more than one way.
Your key is 64 bit, a bit small for today. But that's the least of your worries for now.
I see a non cryptographic PRNG. You need to use a crypto PRNG.
You're reusing a key in a stream cypher. Stream cyphers are notorious for being hard to use correctly. In this mode of operation it basically behaves like a one-time-pad generated by a PRNG. Once you reuse a key in such a mode, your crypto is broken.
Suppose an attacker knows encrypt(p1) and encrypt(p2). Then he can calculate encrypt(p1)-encrypt(p2) which is identical to p1-p2.
Your effective key size is much smaller than 64bit. The sum of chars in a string is <2^16*length. And for most characters it's even <128. So you're key will usually be a number <1000'000. That's trivial to brute force.
Each element in randoms is a byte i.e. 8 bit. A char is 16 bit. So you're not adding modulo 256. Thus you leak information about the encrypted password.
And to improve it, throw out your own algorithm entirely and use a well know, reviewed algorithm. Inventing your own algorithm is a bad idea unless you're a cryptography expert. And even expert make mistakes relatively often.
And do you really need password decryption (i.e. is it a password store), or is password hashing enough?
My suggestion is to put your master password in a key-derivation-function (PKDF2 is a common choice). Then use the key this function returns to encrypt the rest of your data file using AES.
Related
I'm made one register and loggin form and code.
its ok. I encript my passwords like this:
public static function Hash($password) {
$hash = "f6e649b8fc4c9e35eda6969660e36a2e";
$crypt = md5($password . ($hash));
return $crypt;
}
Why i do to decrypt this?
Thankyou;
This is a very unsafe way to hash a password. The salt is static, so it cannot not fullfill its purpose and MD5 is ways too fast for hashing passwords (one can brute-force about 100 Giga MD5 per second with common hardware).
PHP offers an easy and safe method password_hash() to hash passwords, which handles all the tricky parts like generating a safe salt:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
I have read several places now which basically advise against storing a password in source code, and I understand the reasons.
I have two apps: one for encryption and one for decryption. Data is encrypted to a file on a server; this file is downloaded and decrypted on a client's machine, and then processed by a proprietary app (not mine). The data is sensitive and, (ideally) is meant to be only accessible to the processing app.
As it stands I am using a symmetric key algorithm since the data is large enough. The password is hardcoded into the source code as a string - I know, bad for several reasons.
What I would like to know is what's the best way to store the password? My thought is to use an asymmetric key algorithm e.g. RSA, just for the password, but can't wrap my head around how to do this and if it even makes sense in my scenario. I'd prefer not introduce another file for distribution. I don't know much about decompiling, but I figured implementing a PBKD into the client app would pose the same problem. Cryptography is new to me as you can tell, and using this great forum.
Please don't use symmetrical keys in source files. You can use RSA without introducing another file. As opposed to symmetrical keys, the public key can be hard-coded in source code without any security issues, iff you can guarantee the integrity of the source file. Then again, if someone manages to change it, decryption won't work or there is a man-in-the-middle (MITM) attack going on (and you wouldn't know about it).
CAVEATS
This approach suffers from susceptibility of a MITM attack. An appropriate countermeasure would be to sign the data, but then you are stuck handling the keys and is really a separate question.
Keys are not forever, the key-pair you generate needs to be rotated from time to time.
Make the keys big enough (at least 2048 bits).
Revocation needs to be done manually by you. If you need a more automated solution, consider looking at PKI and OSCP Responders (with or without stapling).
If the data you are sending is large, RSA operations will be lengthy.
Ok, with that out of the way, let's dig in. The example code is written entirely with JDK 8.
First, generate a key-pair. This needs to be done once or every time you need to rotate:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = kpg.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
byte[] pubEnc = publicKey.getEncoded();
byte[] privKeyEnc = privateKey.getEncoded();
System.out.println(Base64.getEncoder().encodeToString(pubEnc));
System.out.println(Base64.getEncoder().encodeToString(privKeyEnc));
Let's say the public key was (these are actual keys I generated, don't use these):
private static final String PUBLIC_KEY_BASE64 =
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCGue
5TCdPJt08w7crbvWjfcSUy/xXjzjjjjPDP7D8PNSnn
CUeNcGWsR/Pd3eoBjmrAy/4Rl8JlHylRry8pX7Zpcz
iQB8wWQdpkSoArjeu4taeFn/45+eg4J5mzmIzFG9F5
wF7N+SeSvtq3E3Q0mtJRRZZJYgNkFmeDuOQjljJVZw
IDAQAB";
and the private key was:
private static final String PRIVATE_KEY_BASE64 =
"MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAg
EAAoGBAIa57lMJ08m3TzDtytu9aN9xJTL/FePOOOOM
8M/sPw81KecJR41wZaxH893d6gGOasDL/hGXwmUfKV
GvLylftmlzOJAHzBZB2mRKgCuN67i1p4Wf/jn56Dgn
mbOYjMUb0XnAXs35J5K+2rcTdDSa0lFFlkliA2QWZ4
O45COWMlVnAgMBAAECgYBAWTIRi1ISuHEkh48qoS8j
+eCwmNGVuvvFA55JUSdVVikrZm08iwCk5sD9qW6JS8
KFT2mMcZWxws5za171PffbeHoIFaNI5n5OXJa4meZA
cgl4ae5su89BjvfzDF2gsnBHwLpgsT0aVdIDQ5BGtL
WzRwZCogY6lZhBOQZAaNFYIQJBALr2+kT+pkSlxrrR
tMxK7WL+hNO7qOIl/CTBuAa6/zTtoEjFMFQBY//jH+
6iabHDfKpaFwh6ynZTXZsb7qIKOM8CQQC4eRAH1VEo
iofZNnX3VjiI5mLtV8rc8Jg+wznN+WFnwdNoLK8y9t
EcuKxg3neIJAM70D6l0IhBfza1QAqQh4/pAkA5vyLZ
wJV2SoWxGihvmQztMJOyGho1j2nrqHHAkm1U2bhSAa
XFrJBIbsxkFoHyx+BvdVf75IE4PtOAnwX7wpB9AkBQ
7CKBHS2N+D8hpQdYqcUBIPdyoFmIVC6lEaTw2x3Ekz
027KsqUyVmUQilMdIDsbCNc4uX14N+H90S43X+8sjJ
AkAKsvRbZ0Au9JytSRKSB7vYl37283zHoQ5jyYUE7x
g7C6nWSl1GEa6khZ47hFAj9C2bdLJ6GtjTleFsVCsR
LUoG";
The keys above are line wrapped for formatting reasons.
Let's say args[0] was "attack at dawn!" and you client looks like this:
public static void main(String[] args) throws Exception {
byte[] pubKey = Base64.getDecoder().decode(PUBLIC_KEY_BASE64);
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pubKey));
Cipher cipher = Cipher.getInstance("RSA");
Cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String encryptedData = Base64.getEncoder().encodeToString(cipher.doFinal(args[0].getBytes("UTF-8")));
System.out.println("Encrypted data is: " + encryptedData);
}
Output: Encrypted data is:
cDoPpQYc6qibrBl5jdENcV+g6HslQDlo9potca5rQxecnxR3Bd/e1T0njqUMACl7x7AG3foGxqZyyUIMrOVXcnw/ux7BgQcg+RDZhSVFQAd5kUGI96pw8WtDVo1N1+WEfaaPhK9CpwUKUxtwR0t27n+W0vhFCqNTEGhofLt8u9o=
The server:
public static void main(String[] args) throws Exception {
byte[] privKey = Base64.getDecoder().decode(PRIVATE_KEY_BASE64);
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privKey));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] encryptedData = Base64.getDecoder().decode(args[0]);
byte[] decryptedData = cipher.doFinal(encryptedData);
System.out.println("Decrypted message was: " + new String(decryptedData, "UTF-8"));
}
Output: Decrypted message was: attack at dawn!
One cool thing about the JDK's RSA implementation is that it uses Optimal Asymmetric Encryption Padding (OAEP) from PKCS#1, which has the effect that even identical messages will look different from each encryption.
Like previous commenters have mentioned, without seeing the full picture, there may be other security problems to address. But for what it's worth, I think this approach is better than using symmetrical keys, which still can be used with this encryption scheme. Then you would get what's called a hybrid cryptosystem, but there are APIs that do this for you.
Instead of storing the plaintext password in the source and checking against that you can store the encrypted password in the source (hard coded).
Then the user can enter the password, the code encrypts the password and compare the result of the encryption with the stored encrypted value to see if the password match. The password entered (not the encrypted password) is then used to encrypt/decrypt the data.
The encryption used should make the effort to reverse the encrypted password to the plaintext password hard/impossible.
Example:
You choose the encryption/decryption password to be This is my password1 (the one that is currently in the sources).
You encrypt the password with for instance SHA-256 and hard code it in the source: 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c.
Encrypt/decrypt app prompt for password.
User enter password.
App calculates the SHA-256 of the entered password and compare the result to 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c
If it matches the data is encrypted/decrypted with entered password This is my password1 using your code already in place.
If it does not match, give an error.
A hacker gets your sources and have access to the hash 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c and the algorithm you used. But he needs the This is my password1 password to decrypt the data. He can reverse or brute force the hash but that takes effort and time.
One can use seeds etc, but to keep them secret is then again the same issue.
It is probably not the most secure, I am no expert but it is better than having This is my password1 in the sources.
I am working on a Java project where I must ensure the confidentiality and integrity of users password saved in a plaintext file.
To do so, I will write only a hash of the password in the file. More specifically, my intention is to write the hash of the password and a random salt, plus the random salt itself, to avoid the use of rainbow and lookup tables. I also want to use key-stretching with PBKDF2, to make the computation of the hash computationally expensive.
Finally, I would like to use a keyed hash algorithm, HMAC, for a final layer of protection.
I am trying to implement my thoughts in a Java code, and I have found some examples of the operations that I have presented above:
private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return skf.generateSecret(spec).getEncoded();
}
The thing that I really cannot understand is how to input my secret key as the key used by the HMAC algorithm, as it doesn't seem an input to the function. I have looked through the Java documentation, but I cannot find a solution to my question.
At this point, I am not really sure if I understood correctly how the different part of the encryption mechanism work, so I would accept any help on the topic.
I think I see the confusion. You're apparently expecting your code to apply PBKDF2 then HMAC-SHA-1. That's not how it works: HMAC-SHA-1 is used inside PBKDF2.
The gist of PBKDF2 is to apply a function repeatedly which has the following properties:
it takes two arguments;
it returns a fixed-size value;
it is practically undistinguishable from a pseudo-random function.
HMAC-SHA-1 is such a function, and a common choice. There are other variants of PBKDF2, using HMAC-MD5, HMAC-SHA-256, or other functions (but these variants aren't in the basic Java library).
PBKDF2 takes two data inputs (plus some configuration inputs): the password, and a salt. If you want to include a secret value in the calculation, PBKDF2's input is the place for it: don't tack on a custom scheme on top of that (doing your own crypto is a recipe for doing it wrong). Append the pepper (secret value common to all accounts) to the salt (public value that varies between accounts).
Note that pepper is of limited usefulness. It's only useful if the hashes and the pepper secret value are stored in different places — for example, if the hashes are in a database and the pepper is in a disk file that is not directly vulnerable to SQL injection attacks.
Is it possible to restore the key from blowfish encrypted ciphertext and plaintext pairs?
I have several strings both encrypted and plain. But I can't remember key.
example of encrypted string 24026B7101030657757D01
decrypted string is AC C1312463
$key = '';
$plaintext = '';
$crypttext = '24026B7101030657757D01';
$cache = array();
while($plaintext != 'AC C1312463')
{
$key = random_string();
while(array_search($key,$cache) !== FALSE)
{
$key = random_string();
}
$cache[] = $key;
$bf = new Crypt_Blowfish($key);
$plaintext = $bf->decrypt($crypttext);
}
print_r($key);
die();
Let's say I have algorithm like this. How should function random_string should look like to get 32bit random key?
No decent cipher (including Blowfish) allows efficient key recovery no matter how many (plaintext, ciphertext) pairs you know.
What remains is a brute-force attack where you guess the key and then check if it matches a known pair. For sufficiently complex keys this becomes prohibitively expensive. So this will only work if your key was bad.
What you are proposing is esentially a known-plaintext attack, that said, as the wiki article points out, they haven't been a successful key recovery mechanism since the days of the Enigma.
To even get close to a modern key recovery system, you need to use a chosen plaintext attack like Differential cryptanalysis, which analyzes differences in ciphertext between specially chosen plaintext pairs to gain info about the key. That said, Blowfish isn't particularly susceptible to such attacks, so it won't help much anyways.
If you want to recover your key, you should consider the mechanisms that were used to generate it (is it derived from a password, how big is it, etc) and then come up with a way to brute force it, whether through a dictionary attack, iterating through all 32 bit integers, etc. a program called John the Ripper may help with applying this brute forcing as efficiently as possible.
when I call getwork on my bitcoind server, I get the following:
./bitcoind getwork
{
"midstate" : "695d56ae173bbd0fd5f51d8f7753438b940b7cdd61eb62039036acd1af5e51e3",
"data" : "000000013d9dcbbc2d120137c5b1cb1da96bd45b249fd1014ae2c2b400001511000000009726fba001940ebb5c04adc4450bdc0c20b50db44951d9ca22fc5e75d51d501f4deec2711a1d932f00000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000",
"hash1" : "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000",
"target" : "00000000000000000000000000000000000000000000002f931d000000000000"
}
This protocol does not seem to be documented. How do I compute the hash from this data. I think that this data is in little endian. So the first step is to convert everything to big endian? Once that is done, I calculate the sha256 of the data. The data can be divided in two chuncks of 64 bytes each. The hash of the first chuck is given by midstate and therefore does not have to be computed.
I must therefore hash the chunck #2 with sha256, using the midstate as the initial hash values. Once that is done, I end up with a hash of chunk 2, which is 32 bytes. I calculate the hash of this chunk one more time to get a final hash.
Then, do I convert everything to little endian and submit the work?
What is hash1 used for?
The hash calculation is documented at Block hashing algorithm.
Start there for the relatively simple basics. The basic data structures are documented in Protocol specification - Bitcoin Wiki. Note that the protocol definition (and the definition of work) more or less assumes that SHA-256 hashes are 256-bit little-endian values, rather than big-endian as the standard implies. See also
Getwork is more complicated and runs into more serious endian/byte ordering confusion.
First note that the getwork API is optimized to speed up the initial steps of mining.
The midstate and hash1 values are for these performance optimizations and can be ignored. Just look at the "data".
And when a standard sha256 implementation is used, only the first 80 bytes (160 hex characters) of the "data" are hashed.
Unfortunately, the JSON data presented in the getwork data structure has different endian characteristics than what is needed for hashing in the block example above.
They all say to go to the source for the answer, but the C++ source can be big and confusing. A simple alternative is the poold.py code. There is discussion of it here: New mining pool for testing. You only need to look at the first few lines of the "checkwork" routine, and the "bufreverse" and "bytereverse" functions, to get the byte ordering right. In the end it is just a matter of doing a reversal of the bytes in each 32-bit segment of the data. Yes - very odd. But endian issues are tricky and can end up that way....
Some other helpful information on the way "getwork" works can be found in discussions at:
Do I understand header hashing?
Stupid newbie question about the nonce
Note that finding the signal to noise in the original Bitcoin forum is getting very hard, and there is currently an Area51 proposal for a StackExchange site for Bitcoin and Crypto Currency in general. Come join us!
It sounds right, there is a script in javascript that do calculate the hash but I do not fully understand it so I don't know, maybe you understand it better if you look.
this.tryHash = function(midstate, half, data, hash1, target, nonce){
data[3] = nonce;
this.sha.reset();
var h0 = this.sha.update(midstate, data).state; // compute first hash
for (var i = 0; i < 8; i++) hash1[i] = h0[i]; // place it in the h1 holder
this.sha.reset(); // reset to initial state
var h = this.sha.update(hash1).state; // compute final hash
if (h[7] == 0) {
var ret = [];
for (var i = 0; i < half.length; i++)
ret.push(half[i]);
for (var i = 0; i < data.length; i++)
ret.push(data[i]);
return ret;
} else return null;
};
SOURCE: https://github.com/jwhitehorn/jsMiner/blob/4fcdd9042a69b309035dfe9c9ddf716119831a16/engine.js#L149-165
Frankly speaking
Bitcoin block hashing algorithm is not officially described by any source.
"
The hash calculation is documented at Block hashing algorithm.
"
should read
The hash calculation is "described" at Block hashing algorithm.
en.bitcoin.it/wiki/Block_hashing_algorithm
btw the example code in PHP comes with a bug (typo)
the example code in Python generates errors when run by Python3.3 for Windows XP 32
(missing support for string.decode)