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
>
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.
I make encryption and decryption using AES/PKCS5/CBC in Python
as I know Java has option AES/CBC/PKCS5.
Python need to make program work as PKCS5.
PKCS5 is an 8 byte block, but when I print AES.block_size in Python, it is printed as 16 byte block.
According to definition of PKCS5, I tried:
text = text + (8 - len(text) % 8) * chr(8 - len(text) % 8)
When I encrypt that text, an error message shows input must be multiple of 16 length.
When I change AES.block_size to 8, all the code works well.
However, I think changing 8 to AES.block_size not fit to definition of PKCS5.
Please help me understand.
Create a paddding function
def pad(text):
pad= AES.block_size - (len(text) % AES.block_size))
assert(pad >= 1 && pad <= AES.block_size)
return text + chr(pad)*pad
and apply the encryption to pad(text) instead.
There are historical reasons why some block sizes correspond to the name PKCS5 and others to PKCS7 or even PKCS8. The padding scheme is the same. One is historically tied to DES (before AES even existed) and all block ciphers in the then current standards (PKCS is such a standard) had 8 byte blocks.
Just use the above for AES and the correct one for AES in Java and you'll be OK in principle.
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)
I'm doing a programming challenge and I'm going crazy with one of the challenges. In the challenge, I need to compute the MD5 of a string. The string is given in the following form:
n[c]: Where n is a number and c is a character. For example: b3[a2[c]] => baccaccacc
Everything went ok until I was given the following string:
1[2[3[4[5[6[7[8[9[10[11[12[13[a]]]]]]]]]]]]]
This strings turns into a string with 6227020800 a's. This string is more than 6GB, so it's nearly impossible to compute it in practical time. So, here is my question:
Are there any properties of MD5 that I can use here?
I know that there has to be a form to make it in short time, and I suspect it has to be related to the fact that all the string has is the same character repeated multiple times.
You probably have created a (recursive) function to produce the result as a single value. Instead you should use a generator to produce the result as a stream of bytes. These you can then feed byte by byte into your MD5 hash routine. The size of the stream does not matter this way, it will just have an impact on the computation time, not on the memory used.
Here's an example using a single-pass parser:
import re, sys, md5
def p(s, pos, callBack):
while pos < len(s):
m = re.match(r'(d+)[', s[pos:])
if m: # repetition?
number = m.group(1)
for i in range(int(number)):
endPos = p(s, pos+len(number)+1, callBack)
pos = endPos
elif s[pos] == ']':
return pos + 1
else:
callBack(s[pos])
pos += 1
return pos + 1
digest = md5.new()
def feed(s):
digest.update(s)
sys.stdout.write(s)
sys.stdout.flush()
end = p(sys.argv[1], 0, feed)
print
print "MD5:", digest.hexdigest()
print "finished parsing input at pos", end
All hash functions are designed to work with byte streams, so you should not first generate the whole string, and after that hash it - you should write generator, which produces chunks of string data, and feed it to MD5 context.
And, MD5 uses 64-byte (or char) buffer so it would be a good idea to feed 64-byte chunks of data to the context.
Take advantage of the good properties of hashes:
import hashlib
cruncher = hashlib.md5()
chunk = 'a' * 100
for i in xrange(100000):
cruncher.update(chunk)
print cruncher.hexdigest()
Tweak the number of rounds (x = 10000) and the length of the chunk (y = 100) so that x * y = 13!. The point is that your are feeding the algorithm with chunks of your string (each one x characters long), one after the other, for y times.
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))