I am working on chrome extension to save some user data to local storage. I encode data with crypto-js.
However I am facing one minor issue/dilemma - if I encode user data using secret key abc123 I get something like this 2FsdGVkX19v0LNG0FKFv1SxAQj4AqdNvWWMGyi9yVI=. However if I decrypt it using another secret key like abc I get empty string. Only the correct secret key return non empty string.
So my question how do I need to encode data, if decoding with wrong key it would still return some string? Is there some configuration for this or different encoding?
If I am a hacker and I am using brute force to crack data it looks pretty obvious, what secret key user is using to encode data.
Fidller to fiddle with configuration.
Since you're using Crypto.js you're limited to popular and battle-tested algorithms. Let's say that you're using AES-256-CBC with a key derived from a password ("abc123").
If you encrypt something that a human uses then it likely has low entropy and therefore some structure to it. Think about some JSON string that you're encrypting. If the attacker tries to decrypt the ciphertext with some random key they might get random bytes. If they know they have to get JSON back, they have an oracle whether the decryption worked. They try again with a different key and get different random bytes. They repeat this until they find a plaintext that has a valid JSON structure. Even when they don't know that it is JSON, they might utilize statistical methods in order to deduce whether they got the right key.
You might need to use gzip before encryption in order to make that deduction harder but then the attacker might just incorporate an ungzip procedure in their bruteforcer and just do the statistical analysis.
AES is a block cipher where changing a single bit in the key changes roughly half the bits in the ciphertext with a constant plaintext. That means the attacker will not be able to see that they are getting closer to the correct key. They will have to try all of them.
The usual way of making it harder for an attacker is to increase the work factor. Crypto.js uses by default EVP_bytestokey with a single iteration of a MD5 hash of the password in order to produce the key. This operation is quite fast. You could change that to something like PBKDF2 with a million iterations but today's computers are so fast that this doesn't solve your problem...
The main issue is that your password is too short. "abc123" is a password that can be bruteforced in milliseconds when using Crypto.js defaults (1xMD5) and maybe minutes when using PBKDF2 with a million iterations. Adding a single character to a password multiplies the bruteforce effort by at least 50 (depending on class: upper, lower, digits, special).
Now you can calculate how long your password should be in order interfere with an attacker that corresponds to your risk appetite.
Note that just having encryption doesn't solve all your problems. Usually, the threat still exists.
You only can decrypt your data with the encryption key.
I personally wouldn't encrypt data in a frontend application.
Maybe you should have a look at the documentation:
https://cryptojs.gitbook.io/docs/
Related
Very simple question, how much data (bytes) do strings take up? Do they take up 1 byte per character?
I tried searching it up, but ws schools doesn't say...
I want to know this to reduce bandwidth in my web app.
Also, for anyone that knows, does socket.io automatically json stringify when using socket.emit();?
String is a character array. So, it will take up roughly sizeof(char) * noOfCharacters ignoring other fields in String class for now. Character can be of 1 byte or 2 bytes depending upon the system, the type of chars being represented- unicode etc.
However, from your question, you are more interested in data being transported over the network. Note that data is always exchanged in bytes (byte[]) and thus string will be converted into byte[] representation first and then ported over.
To limit the bandwidth usage, you can enable compression, choose interoperable serialisation technique(protobuf, smile, fastinfoset etc)
I am struggling at this one part of code where I need to decrypt AES on my server side (Ruby) from a client. I know all the information, but I am struggling with re-producing the encryption.
I am currently using CryptoJS from https://github.com/brix/crypto-js. I am not sure which version of AES it is using which might be my first problem.
An example of how I currently encrypt my data in Javascript is:
encodeURIComponent(CryptoJS.AES.encrypt("Message","Key").toString())
Right now I am currently using openssl and cgi in Ruby to try to decrypt. This is wrong and not working, but I wanted to show what I am trying as I believe it is close. I don't understand how the key is used in the encryption, but I am following the example I found here
require "openssl"
require "cgi"
cipher = OpenSSL::Cipher.new('AES-128-CBC')
cipher.encrypt
key = "Key"
iv = cipher.random_iv
encrypted = cipher.update("Message") + cipher.final
puts CGI::escape(encrypted.to_s)
I have just put "Message" and "Key" to not share my information, I am an amateur when it comes to security and cryptography, but I have done these things in lower level languages without problems. I believe the problem happens in two main areas
My lack of knowledge of how these high level languages work, and the libraries I am using
The strings are sometimes UTF-8 vs UTF-16 in these langauges, so passing the "Message" as a string might be causing problems
FULL EXAMPLE OF ENCRYPTION AND DECRYPTION IN JAVASCRIPT:
Encrypting and URL encoding with input 1:
encodeURIComponent(CryptoJS.AES.encrypt("1","Key").toString())
Result:
"U2FsdGVkX19Lp8ItQaO5h6Lj68sheHeYrIkJAfqt1Tw%3D"
Decoding URL and Decryption:
CryptoJS.AES.decrypt(decodeURIComponent("U2FsdGVkX19Lp8ItQaO5h6Lj68sheHeYrIkJAfqt1Tw%3D"), "Key").toString(CryptoJS.enc.Utf8)
Result:
"1"
At least one of your problems is noted by Artjom B noted in the comment above, and this is a frequent problem with trying to get crypto-js to interoperate with other libraries: crypto-js is not taking in a "Key" the way you are using it but instead a password. Passwords are not keys!!!
Internally, crypto-js uses a very poor algorithm for converting the password into a key. The algorithm is poor for two reasons: (1) it is based upon the insecure MD5, and (2) converting passwords to keys should be a slow process to deter brute force guessing of passwords. In crypto-js, the process is not slow.
To get you headed the right direction, do not call:
CryptoJS.AES.encrypt("Message","Password")
Instead, call
CryptoJS.AES.encrypt("Message", key, { iv: iv });
You might also need to explore padding to get it to interoperate with Ruby.
I need to do a SHA1 hash, the only option is to use Javascript (due to my client using a 3rd party product)
An SHA1 is required to pass some information to a payment gateway. so the following info will need to be passed to a SHA1 to convert to a hash (username, password, amount), then passed to a payment gateway
My question is is it safe? ie can't people just view source and see the things I am hashing? is that recommended? is there any other way to do it?
thanks
Regardless of the hashing algorithm used, with browser-side Javascript, your users will always be able to view the page source and see the things you are hashing.
If you're hashing on the server-side, then the source text is not revealed to the browser. It's extremely difficult to "reverse" a SHA-1 hash, but not "impossible" - with enough brute-force power, you could at least find a hash collision (another string which produces the same hash).
SHA-1 is considered secure enough for most purposes. However, it is not considered secure against major, well-funded opponents - with a few million dollars one can hire enough cloud computing resources to break a SHA-1 hash relatively quickly, and this will become progressively cheaper as computing power increases.
If passwords are involved, you should look into BCrypt.
No, don't do this!
Password hashing is supposed to make somebody who copies your database unable to use the login information. By hashing on the client side you have exactly the value in the database, that needs to be sent in the request. So an attacker would just disable the hashing and use the database value as the password.
Quick overview of password hashing:
Each user has a password, that your service knows. They use it to login. Imagine you stored those in plain text. That would be bad in case someone copies your database. So you hash each password with an algorithm like md5 or sha1. The hash can not be used to recreate the password, but you can check a password if it's valid. Problem solved?
Not quite. It's simple to create a rainbow table for a hashing algorithm. This way you can quickly look up possible input values for each hash. So you salt. This means that each user has a random string that gets appended to the password before hashing, creating a unique hashing function per user. Perfect solution?
Again not quite. If your database is copied, with enough computing power this can be cracked. So your last step is using iterations. You don't just append the salt and hash, but you take that result, append the salt again and hash again. You do this a couple hundred times. This way it becomes more expensive for an attacker to brute force attacks. This is what bcrypt does. Over time computing power increases, so you should increase the number of iterations.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I'm working on a javascript function to encrypt and store passwords on the browser using a 6 digit PIN. While this could easily be brute forced, the server side code prevents this by locking out the account after 3 incorrect attempts.
The example below using AES, only decrypts to plain text when the pin/key is correct. This allows the attacker to try the 99,9999 combinations and pick out the only plain text result, bypassing the server side restrictions.
Can someone recommend a javascript crypto function/library that always decrypts to plain text, even with the incorrect key?
var encrypted = CryptoJS.AES.encrypt("password:abcdefg", "pin:123456");
$('#1').text(encrypted);
var decryptedCorrect = CryptoJS.AES.decrypt($('#1').text(), "pin:123456")
$('#3').text(decryptedCorrect.toString(CryptoJS.enc.Utf8));
var decryptedInCorrect = CryptoJS.AES.decrypt($('#1').text(), "pin:112233")
$('#4').text(decryptedInCorrect.toString(CryptoJS.enc.Utf8));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<div>
Encrypted text: <span id="1"></span>
</div>
<br />
<div>
Decrypted with correct pin: <span id="3"></span>
</div>
<br />
<div>
Decrypted with incorrect pin: <span id="4"></span>
</div>
(Ideally the above should be some plain text value)
In general, this cannot work.
To prevent brute-force guessing attacks like these, not only would you need every key (or at least a fairly large fraction of the keys) to decrypt the ciphertext into valid plaintext, but you'd somehow have to arrange for every key to decrypt the ciphertext into plausible plaintext, convincing enough to pass for the real plaintext at least on a cursory inspection.
In particular, the "fake" plaintext produced on incorrect encryption would need to at least be syntactically valid, so that your own code will accept it, and it would also need to have the same general structure and the same statistical properties as your real plaintext, so that the attacker cannot just use some regexps or letter frequency analysis to guess which of the plaintexts is most likely the correct one.
Basically, if you were encrypting passwords, your decryption method would have to generate a plausible-looking password for any key. If you were encrypting JSON data, it would have to generate valid JSON. If you were encrypting poems, it would have to generate a poem.
And they'd have to be good poems, because who'd bother encrypting bad poetry?
Obviously, no general-purpose encryption algorithm can do this.
So, how can you achieve something like what you want? Basically, you have two options:
You can increase the length of your keys so that they cannot be practically enumerated. If you're using random decimal numbers (actually chosen randomly, not by the user!), then around 25 to 30 digits should be the minimum safe length.
You can cut down the length a bit by using key stretching. For example, if you hash each key 100,000 times before using the result to decrypt the data, then you can cut down your keyspace size by a factor of 100,000, i.e. from 25 digits to 20.
You can also make your keys easier to remember by encoding them as phrases. For example, you could compile a list of 1000 short, common English words (or use an existing list), and replace each group of three digits in your password with the corresponding word in the list. It's a lot easier for most people to remember, say, a sequence of five random words than a random 25-digit number.
The other option, of course, is to make use of the server-side rate limiting you already have. To do that, you need to ensure that the client has to check the key with the server before it can do anything else with it.
That is, you should store the actual encryption key (which could be, say, a random 128-bit binary string) on the server, and have the server only send it to the client after the client has successfully authenticated with its own "short key".
You should also make sure that neither the short nor the long key can be captured by an eavesdropper, e.g. by using something like SRP for the authentication, or simply by doing the authentication over TLS/SSL.
Neither of these solutions is perfect: the first may require inconveniently long keys, even with key stretching, while the second method won't work if the client is offline, and can fail catastrophically is the server is ever hacked. In general, though, those are pretty much the best you can do.
(There are ways to combine the two methods for extra security, so that the attacker would have to both compromise the server and guess the client's password in order to break the system. But then you'd also have the disadvantages of both methods.)
There is format preserving encryption, which directly answers your question. You can look for a library function, but FPE is not commonplace. Instead you should be decreasing your PIN retry counter before you start to decrypt/verify and then increase it again if the PIN decrypts and is correct.
Note that your haphazard scheme is no replacement for TLS and may - and probably has - other vulnerabilities.
I'd like to encrypt and decrypt data with private and public keys, respectively.
The data is between 1 and 32 bytes.
I do not want to use a symmetric cipher for the data - I want to use the keys on the data directly. (This is not normally done for performance reasons, but my data is very small.)
Is this possible and Where should I start?
I'd like to encrypt and decrypt data with private and public keys
Pretty much anyone who's worked with crypto will tell you that you write crypto at your own risk. Use the standard libraries, they're made with all the things that (if you are not aware of these techniques) leave your traffic unsecured.
That said, here's some Python libraries (but you can get this in most languages from PHP to Java or whatever floats your boat):
https://pypi.python.org/pypi/pycrypto
https://www.dlitz.net/software/pycrypto/
Crypto RSA in Python
https://pypi.python.org/pypi/PyECC
You'll see pycrypto because it's popular if you're looking to use RSA. Another package is PyECC which includes functionality for elliptic curve crypto. This is important if you're looking to reduce your key size or have less resources to devote to crypto, usually in mobile systems or something small. The difference in key sizes (link) can get ridiculous as the keys grow (for increased security)
Maybe keyczar is what you're looking for:
http://www.keyczar.org/