two-way keyed encryption/hash algorithm

2020-02-09 08:23发布

I am no way experienced in this type of thing so I am not even sure of the keywords (hence the title). Basically I need a two way function

encrypt(w,x,y) = z

decrypt(z) = w, x, y

Where w = integer 
      x = string (username)
      y = unix timestamp 

and z = is an 8 digit number (possibly including letters, spec isn't there yet.)

I would like z to be not easily guessable and easily verifiable. Speed isn't a huge concern, security isn't either. Tracking one-to-one relationship is the main requirement. Any resources or direction would be appreciated.

EDIT

Thanks for the answers, learning a lot. So to clarify, 8 characters is the only hard requirement, along with the ability to link W <-> Z. The username (Y) and timestamp (Z) would be considered icing on the cake.

I would like to do this mathematically rather than doing some database looks up, if possible.

If i had to finish this tonight, I could just find a fitting hash algorithm and use a look up table. I am simply trying to expand my understanding of this type of thing and see if I could do it mathematically.

7条回答
爱情/是我丢掉的垃圾
2楼-- · 2020-02-09 08:57

I can't tell if you are trying to set this up a way to store passwords, but if you are, you should not use a two way hash function.

If you really want to do what you described, you should just concatenate the string and the timestamp (fill in extra spaces with underscores or something). Take that resulting string, convert it to ASCII or UTF-8 or something, and find its value modulo the largest prime less than 10^8.

查看更多
别忘想泡老子
3楼-- · 2020-02-09 09:02

Encryption or no encryption, I do not think it is possible to pack that much information into an 8 digit number in such a way that you will ever be able to get it out again.

An integer is 4 bytes. Let's assume your username is limited to 8 characters, and that characters are bytes. Then the timestamp is at least another 4 bytes. That's 16 bytes right there. In hex, that will take 32 digits. Base36 or something will be less, but it's not going to be anywhere near 8.

查看更多
甜甜的少女心
4楼-- · 2020-02-09 09:04

Hashes by definition are one way only, once hashed, it is very difficult to get the original value back again.

For 2 way encryption i would look at TripleDES which .net has baked right in with TripleDESCryptoServiceProvider.

A fairly straight forward implementation article.

EDIT

It has been mentioned below that you can not cram a lot of information into a small encrypted value. However, for many (not all) situations this is exactly what Bit Masks exist to solve.

查看更多
趁早两清
5楼-- · 2020-02-09 09:08

You probably can't.

Let's say that w is 32 bits, x supports at least 8 case-insensitive ASCII chars, so at least 37 bits, and y is 32 bits (gets you to 2038, and 31 bits doesn't even get you to now).

So, that's a total of at least 101 bits of data. You're trying to store it in an 8 digit number. It's mathematically impossible to create an invertible function from a larger set to a smaller set, so you'd need to store more than 12.5 bits per "digit".

Of course if you go to more than 8 characters, or if your characters are 16 bit unicode, then you're at least in with a chance.

查看更多
放我归山
6楼-- · 2020-02-09 09:08

Let's formalize your problem, to better study it.

Let k be a key from the set K of possible keys, and (w, x, y) a piece of information, from a set I, that we need to crypt. Let's define the set of "crypted-messages" as A8, where A is the alphabet from which we extract the characters to our crypted message (A = {0, 1, ..., 9, a, b, ..., z, ... }, depending on your specs, as you said).

We define the two functions:

crypt: I * K --> A^8.
decrypt A^8 * K --> I

The problem here is that the size of the set A^8, of crypted-messages, might be smaller than the set of pieces of information (w, x, y). If this is so, it is simply impossible to achieve what you are looking for, unless we try something different...

Let's say that only YOU (or your server, or your application on your server) have to be able to calculate (w, x, y) from z. That is, you might send z to someone, and you don't care that they will not be able to decrypt it.

In this case, what you can do is use a database on your server. You will crypt the information using a well-known algorithm, than you generate a random number z. You define the table:

Id: char[8]
CryptedInformation: byte[]

You will then store z on the Id column, and the crypted information on the corresponding column.

When you need to decrypt the information, someone will give you z, the index of the crypted information, and then you can proceed to decryption.

However, if this works for you, you might not even need to crypt the information, you could have a table:

Id: char[8]
Integer: int
Username: char[]
Timestamp: DateTime

And use the same method, without crypting anything.

This can be applied to an "e-mail verification system" on a subscription process, for example. The link you would send to the user by mail would contain z.

Hope this helps.

查看更多
别忘想泡老子
7楼-- · 2020-02-09 09:12

You just need to encrypt a serialization of (w, x, y) with a private key. Use the same private key to decrypt it.

In any case, the size of z cannot be simply bounded like you did, since it depends on the size of the serialization (since it needs to be two way, there's a bound on the compression you can do, depending on the entropy).

And you are not looking for a hash function, since it would obviously lose some information and you wouldn't be able to reverse it.

EDIT: Since the size of z is a hard limit, you need to restrict the input to 8 bytes, and choose a encryption technique that use 64 bits (or less) block size. Blowfish and Triple DES use 64 bits blocks, but remember that those algorithms didn't receive the same scrutiny as AES.

If you want something really simple and quite unsecure, just xor your input with a secret key.

查看更多
登录 后发表回答