Based on Wikipedia, One-Time Pad is an encryption technique that cannot be cracked. How to implement One-Time Pad encryption in Python?
Here is an example implementation
def encrypt(pad, secret):
return ''.join([chr(ord(c) ^ ord(secret[i])) for i, c in enumerate(pad[:len(secret)])])
Now you can use it to encrypt your messages. Remember the pad size should be at least the size of the secret:
secret = 'i am a secret'
pad = '33116f14-9b6f-42c6-9636-3dbd31c0548d'
enc = encrypt(pad, secret)
And you can decipher it with the same function:
assert secret == encrypt(pad, enc)
Related
I using getting the encrypted message from a third party sever.
I am using the tools in enter link description here
to test and its correct
The Encrypted Text =
"WiI9g5qo+ztSlqHMbpiezHZ2dBkQ2gprGJZyWtwcMTWPoxzLsMmujE9xDeFK4XYMfBdZGh2naMwP3LfbPy/06mazrSs66WRM1oxhz56L2UzTKyCWCl+ld7RlN7aPwfEw2j9VN50YCkMLfQRfIAXTspKQb6o5QQw8ey0cINdtWSHClz/uXiCFqiYJfItxY1rAZkE1Qj0b0izGQFJ9/44Zfw0dJtzCXYgXTPZftPeGTdoX/HnZJpUvfqmLIAdgAyoXi5BxL5bgSs30yaB4bRxJJj7DKpVbAgZmx0ecjmiGDh7t78A16pZ2kz+OIUkuc/hxvUaVehsH1pVdqycpUJfbgy+to0AY/+BBd38GGvv8YdTCa99bSHRGaZuUglLKN/2J0pZmfrIARIdgrV2yDK+IN4hTVKf1jprtfvhvkG+eRyDfoLL9rg8+ZEtdYUdZgDdF3ftmHKTzgxI6leMWX7WFRTHjxVYFVk0yWA9xXk6s/WcG6IFeGYPVF94IcLeC2eAjaMasusF+C6qyFWi6nuyFK2Gr1utvG6kg84Hu0KKYg42MHXIR1AtQW3MWaqosb54y0GutQtnD47l84/PdJvUhuE/a7uyfCjjtyh2sRRLX3WDosyRZsqjLea9EIX6oNmQMZd1WRxM86Ggt6bVOc9KY5Z7HLpLyb0lLF4sdyzfBNJB7u7vqkBzsEss1Yq+sXD0N"
Key = "1234567812345678"
And the result
After AES Decrypted Output (Base64):
And after Decode Plain Text
THe result is :
{"upPacketSN":-1,"upDataSN":-1,"topic":"v1/up/ad","timestamp":1619672797621,"tenantId":"2000034792","serviceId":"","protocol":"lwm2m","productId":"15044315","payload":{"APPdata":"MTIzNDU2NzgsNTM0OCwwNywwOCwyNTUsMTc5LDEyOCwwMDAwLDQyNTksMSw2LDAsMCwwLDAsMCwwLDI0LDMuNzAsMy43MCwxLDEsNiwsMCwwLDAsMCwwLDAsMCwwLDAsMCwtMjU1LC0yNTUsLTI1NSwxLjY5LDEuOCw0OTk4LDYwLDE0NDAsNjA="},"messageType":"dataReport","deviceType":"","deviceId":"523ede8bb7e34dd4a1bd74028d63749e","assocAssetId":"","IMSI":"undefined","IMEI":"864162041961023"}
One of the thing is that IV must be NULL to get the correct answer.
And so if i implement in Python AES CBC using pycryptodome library in the following like:
class AES_CBC:
def add_to_16(self, value):
while len(value) % 16 != 0:
value += '\0'
return str.encode(value) # 返回bytes
#解密方法
def decrypt_oralce(self, key, text):
# 初始化加密器
# 偏移量 16个0
iv = "0000000000000000"
aes = AES.new(self.add_to_16(key), AES.MODE_CBC, self.add_to_16(iv))
#优先逆向解密base64成bytes
base64_decrypted = base64.decodebytes(text.encode(encoding='utf-8'))
#
decrypted_text = str(aes.decrypt(base64_decrypted), encoding='utf-8') # 执行解密密并转码返回str
unpad = lambda s : s[0:-ord(s[-1])]
#PADDING = '\0'
#print decrypted_text.rstrip(PADDING) #zeropadding只见诶去掉结尾\0
# print(unpad(decrypted_text))
return unpad(decrypted_text)
if __name__ == '__main__':
aes = AES_CBC()
#加密
key = "1234567812345678"
enc_msg = "WiI9g5qo+ztSlqHMbpiezHZ2dBkQ2gprGJZyWtwcMTWPoxzLsMmujE9xDeFK4XYMfBdZGh2naMwP3LfbPy/06mazrSs66WRM1oxhz56L2UzTKyCWCl+ld7RlN7aPwfEw2j9VN50YCkMLfQRfIAXTspKQb6o5QQw8ey0cINdtWSHClz/uXiCFqiYJfItxY1rAZkE1Qj0b0izGQFJ9/44Zfw0dJtzCXYgXTPZftPeGTdoX/HnZJpUvfqmLIAdgAyoXi5BxL5bgSs30yaB4bRxJJj7DKpVbAgZmx0ecjmiGDh7t78A16pZ2kz+OIUkuc/hxvUaVehsH1pVdqycpUJfbgy+to0AY/+BBd38GGvv8YdTCa99bSHRGaZuUglLKN/2J0pZmfrIARIdgrV2yDK+IN4hTVKf1jprtfvhvkG+eRyDfoLL9rg8+ZEtdYUdZgDdF3ftmHKTzgxI6leMWX7WFRTHjxVYFVk0yWA9xXk6s/WcG6IFeGYPVF94IcLeC2eAjaMasusF+C6qyFWi6nuyFK2Gr1utvG6kg84Hu0KKYg42MHXIR1AtQW3MWaqosb54y0GutQtnD47l84/PdJvUhuE/a7uyfCjjtyh2sRRLX3WDosyRZsqjLea9EIX6oNmQMZd1WRxM86Ggt6bVOc9KY5Z7HLpLyb0lLF4sdyzfBNJB7u7vqkBzsEss1Yq+sXD0N"
#解密
dec_text = aes.decrypt_oralce(key, enc_msg)
print(key)
print(dec_text)
EDITED:
i got a different result using same IV 16'0'
and
the result from the web is
{"upPacketSN":-1,"upDataSN":-1,"topic":"v1/up/ad","timestamp":1619687373640,"tenantId":"2000034792","serviceId":"","protocol":"lwm2m","productId":"15044315","payload":{"APPdata":"MTIzNDU2NzgsNTM0OCwwNywwOCwyNTUsMTc5LDEyOCwwMDAwLDQ1MDQsMSw2LDAsMCwwLDAsMCwwLDI0LDMuNzAsMy43MCwxLDEsNiwsMCwwLDAsMCwwLDAsMCwwLDAsMCwtMjU1LC0yNTUsLTI1NSwxLjY5LDEuOCw0OTk4LDYwLDE0NDAsNjA="},"messageType":"dataReport","deviceType":"","deviceId":"523ede8bb7e34dd4a1bd74028d63749e","assocAssetId":"","IMSI":"undefined","IMEI":"864162041961023"}
while the result of my code is :
KE#`QS[UDc~
1,"upDataSN":-1,"topic":"v1/up/ad","timestamp":1619687373640,"tenantId":"2000034792","serviceId":"","protocol":"lwm2m","productId":"15044315","payload":{"APPdata":"MTIzNDU2NzgsNTM0OCwwNywwOCwyNTUsMTc5LDEyOCwwMDAwLDQ1MDQsMSw2LDAsMCwwLDAsMCwwLDI0LDMuNzAsMy43MCwxLDEsNiwsMCwwLDAsMCwwLDAsMCwwLDAsMCwtMjU1LC0yNTUsLTI1NSwxLjY5LDEuOCw0OTk4LDYwLDE0NDAsNjA="},"messageType":"dataReport","deviceType":"","deviceId":"523ede8bb7e34dd4a1bd74028d63749e","assocAssetId":"","IMSI":"undefined","IMEI":"864162041961023"}
can anyone help me which part i get wrong?
Thanks
Currently the code is not using a "null-IV", which means an array filled with bytes set to zero. Instead it is using an array filled with '0' characters, which have value 0x30 in hexadecimals or 48 in decimals; distinctly not zero.
To create a null-IV please have a look here on how to indicate byte values within byte arrays in Python. The same trick is used within the add_to_16 loop, where the \0 escape is used to indicate a zero byte.
Note that padding a key or IV is very bad practice. Those need to consist of randomized bytes. Beware that working crypto code is not the same thing as secure crypto code, which should probably be your goal.
for a university exercise I want to develop a simple hotp server-client system in python. In this case the client sends a password and a one time password to the server. The server knows the secret, calculates the current hotp and compares the values it receives. So far, so good. With plaintext this works perfectly fine and the calculated values are the same I get when I use the iOS App "OTP Auth". But there is also the possibility to calculate the OTP in combination with base32. So I added a few lines to encode the plaintext to base32 but now the output in not correct.
Let's assume we're using the secret "1234" so the plaintext output would be "110366". That's working. But if I'm encoding the secret to base32 the output should be "807244" but my program calculates "896513". Anybody know why this is happening?
I've already tried to use different secrets and checked it on different apps. Always the same result.
import hmac
import hashlib
import array
import base64
counter = 0
digits = 6 #Anzahl der Zeichen
def hotp(secret, c):
global digits
counter = extendCounter(c)
hmac_sha1 = hmac.new(secret, counter, hashlib.sha1).hexdigest()
return truncate(hmac_sha1)[-digits:]
def truncate(hmac_sha1):
offset = int(hmac_sha1[-1], 16)
binary = int(hmac_sha1[(offset * 2):((offset * 2) + 8)], 16) & 0x7fffffff
return str(binary)
def extendCounter(long_num):
byte_array = array.array('B')
for i in reversed(range(0, 8)):
byte_array.insert(0, long_num & 0xff)
long_num >>= 8
return byte_array
def main():
secret = "1234"
bSecret = secret.encode("UTF-8")
bSecret = base64.b32encode(bSecret)
otp = hotp(bSecret, counter)
one_time_password = otp
I expect 807244 as the output but the output is 896513
First, it's important to point out that the result of secret.encode('UTF-8') has exactly the same type as the result of base64.b32encode(bSecret) (and for that matter base64.b64encode(bSecret)) -- they all return bytes objects. Also worth noting is that the implementation of hmac in Python has no mention of base64/base32 encoding. So the short answer is that your expected result of 807244 is only valid if the shared secret is a base64/UTF-8 encoded blob.
This quick snippet shows that really you can give any bytes you like to hotp and it will come up with some result (because hotp is called multiple times in the example, counter is changed)
# ... everything from your example above ...
secret = "1234"
secret_bytes = secret.encode("UTF-8")
secret_bytes
>>> b'1234'
b32_secret = base64.b32encode(bSecret)
b32_secret
>>> b'GEZDGNA='
b64_secret = base64.b64encode(bSecret)
b64_secret
>>> b'MTIzNA=='
hotp(secret_bytes, counter) # just a UTF-8 blob works
>>> '110366'
hotp(b32_secret, counter) # base32/UTF-8 also works
>>> '896513'
hotp(b64_secret, counter) # base64/UTF-8 works as well
>>> '806744'
If you have more detail of why you expected 807244 for a base32/UTF8 blob, I'll be happy to amend this answer.
Found the mistake:
Instead of translating the secret to base32, the secret must be a Base32 decoded value. Also instead of encoding this value, it must be decoded ("base64.b32decode(bytes(saved_secret, 'utf-8'))")
So the correct main looks like this:
def main():
secret = "V6X27L5P" #Base32 value
secret = base64.b32decode(bytes(secret, 'utf-8'))
one_time_password = hotp(secret, counter)
Why is this transposition decryption code not working with some keys?
def transencrypt(word,key):
'''Traspositon encryption function. This function is used to encrypt a line
using the transposition encryption method. To know how transpositon encryption
works you can visit here https://en.wikipedia.org/wiki/Transposition_cipher.'''
count1=0
count2=0
encrypted=''
encryptbox=['']*key
while count1<key:
count2=count1
while count2<len(word):
encryptbox[count1]+=word[count2]
count2+=key
encrypted+=encryptbox[count1]
count1+=1
return encrypted
def transdecrypt(word,key):
'''This Function is for the decrypting the encrypted strings encrypted by
transencrypt().This function only requires the encrypted string and the key
with which it has been decrypted.'''
import math
count1=0
count2=0
decrypted=''
col=int(math.ceil(len(word)/key))
decryptbox=['']*col
while count1<col:
count2=count1
while count2<len(word):
decryptbox[count1]+=word[count2]
count2+=col
decrypted+=decryptbox[count1]
count1+=1
return decrypted
print(transencrypt('hello world',5))
print(transdecrypt('h dewlolrol',5))
OP's original code source
I have tried encrypting "hello world" with key 5, but at the time of decrypting I am getting the wrong result. Using other keys works fine.
The problem is that the string length (11) doesn't divide evenly into the key (5), so the string "hello world" encodes into the groups h d-ew-lo-lr-ol i.e. "h dewlolrol". Which is fine, but the decrypt routine chops "h dewlolrol" into h d-ewl-olr-ol and generates the wrong result, "heoo wlldlr".
A couple of possible ways to fix this:
1) Replace the encryptbox string with an array and pad the encryption units into even width segments: h d-ew -lo -lr -ol i.e. "h dew lo lr ol "
This will allow your decrypt routine to work but you'll end up with spaces at the end of the decryption and the encrypted string will be a different size than the original.
OR
2) Dynamically adjust your decryption logic to figure out, based on the length of the remaining string to decode, and remaining number of expected segments, how much the segments must shrink. This means your decrypt routine can't be as similar to the encrypt routine as it is now. But it will allow you to handle the output of the current encrypt routine and the encrypted string can remain the same length as the original.
Below is a rough rework along the lines of approach #2 above -- you can see it allows the encrypt routine to remain simple but the decrypt routine has to be more complex to make up for it:
import math
def transencrypt(string, key):
'''
Transpositon encryption function. This function is used to encrypt a line
using the transposition encryption method. To learn how transpositon encryption
works you can visit here https://en.wikipedia.org/wiki/Transposition_cipher.
'''
encrypted = ''
length = len(string)
for start in range(key):
for offset in range(start, length, key):
encrypted += string[offset]
return encrypted
def transdecrypt(string, key):
'''
This function is for the decrypting the strings encrypted by
transencrypt(). This function only requires the encrypted
string and the key with which it was decrypted.
'''
decrypted = ''
length = len(string)
width = int(math.ceil(length / key))
for start in range(width):
offset = start
remaining_key = key
remaining_length = length
remaining_width = width
while offset < length:
decrypted += string[offset]
offset += remaining_width
remaining_key -= 1
if remaining_key > 0:
remaining_length -= remaining_width
remaining_width = int(math.ceil(remaining_length / remaining_key))
return decrypted[:length]
if __name__ == '__main__':
import sys
string = sys.argv[1]
key = int(sys.argv[2])
print(transencrypt(string, key))
print(transdecrypt(transencrypt(string, key), key))
**OUTPUT*
> python3 test.py "hello world" 5
h dewlolrol
hello world
>
I'm trying to encrypt some data from python (Google App Engine) and then decrypt it on iOS.
There are several issues surrounding this based on the fact that there are so many options with AES Encryption and the different formats available in Python and Objective-C.
Because of the limited availability of the PyCrypto libraries on Google App Engine and the AES code on the iOS/Objective-C side requiring PKCS7Padding, I decided to use slowAES on the python side.
I'm also using a 16-bit key, CBC Mode, and PKCS7Padding.
Given that, this is my encrypt function and helper variables/function:
def str2nums(s):
return map(ord, s)
key = "hjt4mndfy234n5fs"
moo = aes.AESModeOfOperation()
iv = [12, 34, 96, 15] * 4
CBC_mode = moo.modeOfOperation['CBC']
nkey = str2nums(key)
def encrypt(plaintext):
funcName = inspect.stack()[0][3]
logging.debug("Enter " + funcName)
logging.debug("Input string: " + plaintext)
m, s, encData = moo.encrypt(plaintext, CBC_mode, nkey, len(nkey), iv)
fmt = len(encData)*'B'
dataAsStr = ""
for j in encData:
dataAsStr = dataAsStr + str(j) + ","
logging.debug("Output encrypted data:[" + dataAsStr + "]")
encoded = base64.b64encode(struct.pack(fmt, *encData))
logging.debug("Output encrypted string: " + encoded)
decoded = struct.unpack(fmt, base64.b64decode(encoded))
decrypted = moo.decrypt(decoded, s, CBC_mode, nkey, len(nkey), iv)
logging.debug("Output decrypted back: " + decrypted)
return encoded
Note that on the Python side, I am encrypting, packing, and then base64 encoding the data. Before returning this encrypted data, I'm also doing a test run at decrypting it just to show that in the logs and it does indeed work.
On the iOS side, I'm using the following AES NSData addition:
- (NSData *)AES128DecryptWithKey:(NSString *)key {
// 'key' should be 16 bytes for AES128, will be null-padded otherwise
char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
And I'm making use of this when I pull down the base64/packed/encrypted data like so:
NSMutableString * result = [[NSMutableString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
if (LOG) { NSLog(#"Base64 encoded / Encrypted string: %#", result); }
NSData* encryptedData = [NSData decodeBase64ForString:result]; // base64 decode
if (LOG) { NSLog(#"Encrypted string: %#", encryptedData); }
NSData* decryptedData = [encryptedData AES128DecryptWithKey:#"hjt4mndfy234n5fs"]; // AES Decrypt
The problem is, I can't seem to get the data to decrypt correctly on the client (iOS) side even though it decrypts just fine on the server (in python).
During the decryption, the cryptStatus always ends up : kCCAlignmentError. Which I don't quite understand.
I've also messed with AES 256 but I need a 32bit key I think and that doesn't seem to be an option for slowAES in CBC mode (at least according to the examples?).
Logging of the Server (Notice the actual unencrypted data is merely an empty set [] . That's a JSON representation of such to return to the client.
2012-01-04 08:48:13.962
Enter encrypt
D 2012-01-04 08:48:13.962
Input string: []
D 2012-01-04 08:48:13.967
Output encrypted data:[4,254,226,26,101,240,22,113,44,54,209,203,233,64,208,255,]
D 2012-01-04 08:48:13.967
Output encrypted string: BP7iGmXwFnEsNtHL6UDQ/w==
D 2012-01-04 08:48:13.971
Output decrypted back: []
Logging of the client (iOS):
2012-01-04 12:45:13.891 Base64 encoded / Encrypted string: BP7iGmXwFnEsNtHL6UDQ/w==
2012-01-04 12:45:13.892 Encrypted string: <04fee21a 65f01671 2c36d1cb e940d0ff>
2012-01-04 12:45:29.126 Decrypted string:
So my questions are:
What does it mean by an "Alignment Error"? Or what am I doing wrong that it doesn't want to decrypt on the client?
Do I need to worry about unpacking the data at all considering it looks like it matches up just fine? And if so, how would I go about an unpack() function in C or Objective-C?
Is there just plain a better way to do AES encryption between Google App Engine and iOS?
EDIT: I should also note that besides the answer of using the same Initialization Vector, I found a discrepancy between the python and iOS code for the padding. The encrypt/decrypt worked fine for small amounts of data but then I ran into failure to decrypt with larger ones. I fixed this by changing the iOS side to NOT use PKCS7Padding and put 0 there instead.
The IV needs to match on both ends.
The IV (initialization vector) is a string of bytes that's sent through the encryptor/decryptor to place its "memory" in a pseudo-random state before the "real" data is sent through. Since the encryption results depend on what's gone through before, this initialization makes it impossible (without knowing the IV) for a malicious 3rd party o know whether a given cleartext and key could have produced a given cypertext.
Ideally the IV is itself somehow variable, based, perhaps, on a serial number or some other text that's sent along with the cyphertext, or based on a counter that's synchronized between ends.
The presence of the IV (even if semi-predictable) significantly increases the difficulty of using a "known cleartext" attack. This is especially important for relatively short, frequent messages.
I'm trying to RSA encrypt a word 2 characters at a time padding with a space using Python but not sure how I go about it.
For example if the encryption exponent was 8 and a modulus of 37329 and the word was 'Pound' how would I go about it? I know I need to start with pow(ord('P') and need to take into consideration that the word is 5 characters and I need to do it 2 characters at a time padding with a space. I'm not sure but do I also need to use <<8 somewhere?
Thank you
Here's a basic example:
>>> msg = 2495247524
>>> code = pow(msg, 65537, 5551201688147) # encrypt
>>> code
4548920924688L
>>> plaintext = pow(code, 109182490673, 5551201688147) # decrypt
>>> plaintext
2495247524
See the ASPN cookbook recipe for more tools for working with mathematical part of RSA style public key encryption.
The details of how characters get packed and unpacked into blocks and how the numbers get encoded is a bit arcane. Here is a complete, working RSA module in pure Python.
For your particular packing pattern (2 characters at a time, padded with spaces), this should work:
>>> plaintext = 'Pound'
>>> plaintext += ' ' # this will get thrown away for even lengths
>>> for i in range(0, len(plaintext), 2):
group = plaintext[i: i+2]
plain_number = ord(group[0]) * 256 + ord(group[1])
encrypted = pow(plain_number, 8, 37329)
print group, '-->', plain_number, '-->', encrypted
Po --> 20591 --> 12139
un --> 30062 --> 2899
d --> 25632 --> 23784
If you want to efficiently code the RSA encryption using python, my github repository would definitely to understand and interpret the mathematical definitions of RSA in python
Cryptogrphic Algoritms Implementation Using Python
RSA Key Generation
def keyGen():
''' Generate Keypair '''
i_p=randint(0,20)
i_q=randint(0,20)
# Instead of Asking the user for the prime Number which in case is not feasible,
# generate two numbers which is much highly secure as it chooses higher primes
while i_p==i_q:
continue
primes=PrimeGen(100)
p=primes[i_p]
q=primes[i_q]
#computing n=p*q as a part of the RSA Algorithm
n=p*q
#Computing lamda(n), the Carmichael's totient Function.
# In this case, the totient function is the LCM(lamda(p),lamda(q))=lamda(p-1,q-1)
# On the Contrary We can also apply the Euler's totient's Function phi(n)
# which sometimes may result larger than expected
lamda_n=int(lcm(p-1,q-1))
e=randint(1,lamda_n)
#checking the Following : whether e and lamda(n) are co-prime
while math.gcd(e,lamda_n)!=1:
e=randint(1,lamda_n)
#Determine the modular Multiplicative Inverse
d=modinv(e,lamda_n)
#return the Key Pairs
# Public Key pair : (e,n), private key pair:(d,n)
return ((e,n),(d,n))