Mostrando entradas con la etiqueta Seguridad de la Información y Criptografía. Mostrar todas las entradas
Mostrando entradas con la etiqueta Seguridad de la Información y Criptografía. Mostrar todas las entradas

1 de noviembre de 2012

Steganography

Seguridad de la Información y Criptografía
Homework 8 - Program 4

The hidden code in the images of the last publication was in the images 1, 2 and 5

The homework was create a program to hide a text in an image file or an audio file, it is called Steganography.

Steganography is the art and science of writing hidden messages in such a way that no one, apart from the sender and intended recipient, suspects the existence of the message, a form of security through obscurity. [1]

I create two python programs, one for hide the text (in this case my own code), and other for get again the hidden text.

First of all, I read the PDF that is at the end of this publication, where they explain why is common to hide text in bitmap images, and a introduction to how to change data of the image.

A little introduction about the bitmap images, is how the bytes are arranged, the next is what information is stored in the first bytes of the file.

Header of the file:
Bytes - Description
0-1 Bitmap identifier (BM)
2-5 Bitmap file size
6-9 Reserved
10-13 Bitmap data offset

Information about the file:
Bytes - Description
14-17 Bitmap header size
18-21 Bitmap image width
22-25 Bitmap image height
28:29 Bitmap color depth
26-27 Number of color planes
28:29 Bitmap color depth
30-33 Bitmap compression method
34-37 Bitmap data size
38-41 Bitmap image horizontal rule
42-45 Bitmap image vertical resolution
46-49 Number of colors used
50-53 Number of important colors used

*Information extracted from the PDF in the references.

The rest of the bytes are the image information. In my case I used images with a extension of color of 32 bits per pixel, so are 4 bytes in each pixel, we know that colors are composed by three elemental color, and a fourth in this case that is the "transparent color", (red, green, blue, alpha).

I only made changes in the byte of color red. Per byte we have 8 bits, and I only used the last bit to hide one bit of the complete hidden code.

Example:
If the letter "i" in binary is 01101001, in the first 8 bytes where the color red is stored, I change something like that.

Original - Changed
01010011 - 01010010
01010000 - 01010001
01001101 - 01001101
01001110 - 01001110
01001011 - 01001011
01001001 - 01001000
01001010 - 01001010
01001001 - 01001001

Code



The first parameter in the program is the original bitmap file, then a file with the code and the name of the new image.

~$ python stegano.py "images/rmn-01.bmp" "code_file" "rmn-01.bmp"
Identifier  BM
File size 810054
Reserved 0
Data offset 54
Width  450
Height  450
Text file size 2315
~$

The file with the code look like this.


Then the program to find the code in the image.


In this case the program only needs the bitmap file with the hidden code, and a file name to save the text.

~$ python decode.py "rmn-01.bmp" "decoded"
Image size 810054
~$

If we open the file created, we can see the code in it. After the end of the code we have waste information, because we don't know how many bytes had the original code_file. If we don't want to have waste information at the end, we can include in an specific array of bytes in the beginning, the length of the hidden text.


Image without the hidden text


Image with the hidden text


References:
[1] - Steganography - Definition
Introduction to Bitmap Steganography

31 de octubre de 2012

Steganography

Seguridad de la Información y Criptografía
Homework 8 - Images

Here are my images, three of them with the hidden code that I used.








Try to find the images with the code hidden. Good luck!

25 de octubre de 2012

Stream Ciphers: Edon80

Seguridad de la Información y Criptografía
Homework 7 - Report 3

Edon80 is a stream cypher algorithm designed by Danilo Gligoroski, Smile Markovski, Ljupco Kocarev, and Marjan Gusev. [1]

Has some strengths: [2]
  1. If the needs for security bits have to be increased to arbitrary value, the speed of the cipher would not be affected at all (except initialization phases).
  2. If the size of IV change, it would not affect the speed of the cipher.
  3. It is easily paralelizable.
  4. For achieving high speeds, it is appropriate only for a hardware realization to utilize its more then 80 pipeline and parallel operations.

Edon80 is a hardware binary additive synchronous stream cipher. It belongs to a family of stream ciphers that in hardware can have a constant speed of one bit per clock cycle, but in software implementation on popular modern CPUs can be made as slow as needed.

Since its first description in 2005, it has been analyzed by several cryptographers, have been implemented in a more compact way and a MAC functionality have been added. [3]

How it works?


Edon80 is a binary stream cipher. The keystream in Edon80 is generated as a row of a certain in fnite matrix whose elements are defi ned iteratively using quasigroup operations.

The stream cipher Edon80 uses four fixed quasigroups of order 4. The four quasigroups are the next:

But, why use only that quasigroups or are the unique. In fact, we can generate a different quasigroup if we want, but a quasigroup has a special way to be created, and there are some that are not good for generate a random stream in our case.

In Edon80 we use a quasigroup with a dimension of 4x4, so every row and col need to have a 0, 1, 2 and 3, filled in a table like when we play sudoku. We only need four quasigroups, so the crucial part of this method, was select that quasigroups of a set of 576 options. There are 192 quasigroups and are called fractal quasigroups, since they produce highly regular strings.

Some of the rest 384 after every application of an e-transformation increase the period of the transformed string with smaller coefficient, and other by higher coefficient, and those was discarded. We give a list of 64 quasigroups that increase the period of the transformed string at least 2 times, after every application of an e-transformation by them. For select the four quasigroups of the set of the 64 remaining, each one of them was tested and was found the best four options.

Now we have the general model of the stream cipher Edon80. A key and a Input Vector are required for generate a output stream.


For its proper work Edon80 has the following additional inputs:
  1. One register key of 80 bits to store the actual secret key.
  2. One register IV of 80 bits to store padded initialization vector.
  3. One internal 2-bit counter as a feeder of Edon80 Core in keystream mode.
  4. One 7 bit SetupCounter that is used in IVSetup mode.
  5. One 4 × 4 = 16 bytes ROM bank where 4 quasigroups of order 4 are stored.

In the first row of that table we placed a periodic string that has shape: 01230123[...]0123. The next 80 rows in the table describe 80 e-transformations of that string by using the obtained values of $a_i$ in input vector mode and by the quasigroups $∗i$. The recurrence equations for this transformations are:


The output of the stream cipher is every second value of the last e-transformation so the keystream can be described as:


Using the source code of the official web page of Edon80, I executed a simple example, but I reduced the length of the keystreams:
Generated Key = 04000000000000000000
Generated IV = 0000000000000000
Keystreams generated (3x20 bytes)
s[1]=4E3E5646183CDB17561B8536812775D95D713E69
s[2]=8C67697FD96A249D5E794242413EBEA6B552CC08
s[3]=C61DABCB6AA8E0E50FC5B6392B8549C2F7CBF07B

Encryption of 20 bytes
Plaintext = F4604512C52C03158686A84DF32139B143755F04
Ciphertext = 4E3E5646183CDB17561B8536812775D95D713E69

Decryption of 20 bytes
Ciphertext = 4E3E5646183CDB17561B8536812775D95D713E69
Plaintext = F4604512C52C03158686A84DF32139B143755F04

Attacks and vulnerabilities


Is difficult to attack this kind of stream cipher. Experts found that the complexity of the attack is around 2^69 simple operations for a keystream of similar length. So if we want to attack we have a possibility to found the keystream, but with a brutal force algorithm it will take a very long time.

Another attack and a vulnerability is founded like in others types of encryption and is about the base of explore some periodicy inside the generator.

Using the fact that some elements will repeat with large probability, we can build a kind of test to find out the correct value of the key bits used at the end of the concatenation. We can use it to find a part of the keystream, and is why this kind of stream cipher has a vulnerability.

References:
[1] - Edon80 - Wikipedia
[2] - The eSTREAM Project
[3] - Edon80 Properties
A Key Recovery Attack Of Edon80

18 de octubre de 2012

Bloque Ciphers: OFB - Output Feedback

Seguridad de la Información y Criptografía
Homework 6 - Report 2

The Output Feedback (OFB) mode is a confidentiality mode that requires a unique initialization vector for every message that is ever encrypted under the given key. [1]

The Federal Data Encryption Standard (DES) specifies a crypto-graphic algorithm to be used for the cryptographic protection of sensitive, but unclassified, computer data. This FIPS defines four modes of operation for the DES which may be used in a wide variety of applications. The modes specify how data will be encrypted and decrypted. The modes included in this standard are the Electronic Codebook (ECB) mode, the Cipher Block Chaining (CBC) mode, the Cipher Feedback (CFB) mode, and the Output Feedback (OFB) mode. [2]

This standard is based on the DES and provides the next level of detail necessary for providing compatibility among DES equipment. This standard anticipates the development of a set of application standards which reference it such as communication security standards, data storage standards, password protection standards and key management standards. Cryptographic system designers or security application designers must select one or more of the possible modes of operation for implementing and using the DES in a cryptographic system or security application. [3]

The Output Feedback mode was created by Computer Systems Laboratory and the standard was registered by the National Institute of Standards and Technology.

Difference between the others


The Output feedback has some similarities to the ciphertext feedback mode in that it permits encryption of differing block sizes, but has the key difference that the output of the encryption block function is the feedback, instead of the ciphertext. The XOR value of each plaintext block is created independently of both the plaintext and ciphertext. It is this mode that is used when there can be no tolerance for error propagation, as there are no chaining dependencies. Like the ciphertext feedback mode, it uses an initialization vector. Changing the IV in the same plaintext block results in different ciphertext.

How it works?


The kind of mathematics that this method use is XOR operation, and is the reason why we use the same operation to encrypt and decrypt.

$C_j = P_j \oplus O_j$
$P_j = C_j \oplus O_j$
$O_j = E_k(I_j)$
$I_j = O_{j-1}$
$I_0 = IV$

How to encrypt:

http://upload.wikimedia.org/wikipedia/commons/a/a9/Ofb_encryption.png

How to decrypt:

http://upload.wikimedia.org/wikipedia/commons/8/82/Ofb_decryption.png

We can see in the images that each output feedback block cipher operation depends on all previous ones.

Example


This is a simple example of the output feedback implemented in a python script.
ramon@pavilion:~/Documents$ python outputfeedback.py 
Text: me gusta la clase de cripto
Key: abcdefgh
IV: 12345678
Block size: 8

Block #1
Input block: 12345678
Output block: rtvxz| "
Plaintext: me gusta
Ciphertext: a[vaqqtc
Decrypted: me gusta

Block # 2
Input block: rtvxz| "
Output block: UX[^adgj
Plaintext:  la clas
Ciphertext: UF>^FRJ_
Decrypted:  la clas

Block # 3
Input block: UX[^adgj
Output block: 8<@DHLPT
Plaintext: e de cri
Ciphertext: }<&+H1D?
Decrypted: e de cri

Block # 4
Input block: 8<@DHLPT
Output block: y %*/49>
Plaintext: pto
Ciphertext: +05:?&//
Decrypted: pto

Text: me gusta la clase de cripto

What I did in my program?
  • First my program divide the text in blocks.
  • Then, I use the Input Vector only for the first iteration to get the output block using the key.
  • Using the output block, I encrypt the text block.
  • I get the encrypted text block.
  • In this case, I used the encrypted block text to decrypted at the same time, but it must be separately.
  • Then I use the last output block, for the new input block, and repeat the last steps, until we don't have more text blocks.
  • At the end, I print all the decrypted text block together.

Vulnerabilities


In terms of error correction, output feedback can tolerate ciphertext bit errors, but is incapable of self-synchronization after losing ciphertext bits, as it disturbs the synchronization of the aligning keystream. A problem with output feedback is that the plaintext can be easily altered, but using a digital signature scheme can overcome this problem.

References:
[1] - Block Cipher Modes of Operations
[2] [3] - Standard for DES - Modes of Operation
Definition - Output Feedback
OFB - Examples

20 de septiembre de 2012

Public-key Repository

Seguridad de la Información y Criptografía
Homework 5

The homework for this week is:
Implement a HTTP public-key repository for key exchange that employs RSA-based digital signatures.

My program is running in the web hosting Heroku. I used this host because it's free and I can write code in python. You can see the page in the next url:


The web page must be displayed like the next image:


How this work?


  • Imagine that you are in a Facebook chat, and you are talking with Alice. Then Alice start talking with you but saying strange things, so you aren't sure if is the real Alice.
  • Now you want to verify if is Alice or not, so you send a challenge in the chat.
  • Previously Alice, created a private and a public key for the RSA algorithm, and she is registered in a web service where the public key is stored.
  • Then you enter to the web service, send the challenge showed to Alice.
  • Alice use the script provided in the same web service.
  • In the script she write the x (challenge), her d, and her n. The script returns a response.
  • Alice send the response of the script to you via Facebook chat.
  • You write the response in the web service and click in the verify button.
  • The web service show if is the correct Alice or not.

Code


This is the script where the other person download for get the response:


The python script in the server:


And the template that I created for the page:


Screenshots


When the client don't write the response and click verify.


When the client write a text instead of a number in the response field.


When the verification fails.


Test


I test my app with Juan Espinosa.


And I verify if was the real Juan Espinosa, and was correct.


References:
RSA Algorithm - Elisa Schaeffer

13 de septiembre de 2012

Public Key Algorithms - RSA

Seguridad de la Información y Criptografía
Homework 4

The homework for this week was:
"Implement RSA authentication in Python for a client-server system with sockets."

I will describe what the code should do:
  1. The server open a socket, and wait for a client.
  2. The client start a session with the server.
  3. The server send a random "x" to the client.
  4. The client calculate a f(x) where the function can be anyone.
  5. Get from a user file the (d, n) previously created.
  6. Calculate r = (y^d)mod(n), and send it to the server.
  7. Send to the server the name of the current user and the r.
  8. The server receive the the data, and open a file with a list of all the users.
  9. The server find the correct public key (e, n) from the current user.
  10. The server calculate y = (r^e)mod(n) and get the same "y" that the client calculate.
  11. Verify if the "y" received is equal to f(x) in the server. (This is for authenticate the user)
  12. If the previous sentence was true, send to the client a verification message. (I send "OK" and the client print "Welcome")
  13. If not, close the connection. (My code send form the server "NO" and when the client receive this print "Something was wrong")

Generator of public and private keys



Server



Client



Execution


First of all the folder with the three python files.


I send an argument to the "create keys" program for create 5 users. Create one file per each user with the private key, and all the public keys for all the users are in the file "users".


When we want to run the programs, we need to open two terminals, one for the server and one for the client.

The client receive an argument that indicate the user to use in this running.


The numbers indicate what part of the list was mentioned in the first part in this post. Some numbers aren't in the same sequence that the list and others are omitted becasue the program do it internal and don't have a debug print.

Server:
[1] Socket opened
Sesion started
[3] Sended to the client x = 43
User name:  user3
And received r = 209263
[9] Public key: (349, 225391)
User accepted
Sesion closed
Client:
[2] Connected with the server
Current user:  user3
[5] Private key: (68117, 225391)
The server send me x = 43
[4] After the function f(x) = 1892
[6] My f(x) encrypted, r = 209263
[12] Welcome
Sesion closed
This is the file of user that the server use to find if the current user is allowed or not.


And the keys for the user that I used in the example. Check that the "n" is the same in the use3 in the previous image.


For the function of euclides(), I saw the pseudo-code of the reference [1], and for the gcd() I saw the pseudo-code from the book "Matematica Discreta - Richard Johnsonbaugh".

References:
[1] - Fundamentos matemáticos del método RSA

5 de septiembre de 2012

Diffie-Hellman Key Exchange

Seguridad de la Información y Criptografía
Homework 3

For this week, the homework is:
Hack manually (pencil and paper) a very-short keyed Diffie-Hellman of your choice.

Definition of Diffie–Hellman Key Exchange


Diffie–Hellman key exchange is a specific method of exchanging cryptographic keys. It is one of the earliest practical examples of key exchange implemented within the field of cryptography. The Diffie–Hellman key exchange method allows two parties that have no prior knowledge of each other to jointly establish a shared secret key over an insecure communications channel. This key can then be used to encrypt subsequent communications using a symmetric key cipher. [1]

In the next image we can see how is the channel of communication between Alice and Bob, and like our next example, if we are another person named Eve, we can get the g, p, A, B, and try to hack they key.

[http://upload.wikimedia.org/wikipedia/commons/a/a3/Diffie-Hellman-Schl%C3%BCsselaustausch.png?uselang=es]

My Hacking


Like the example of the image, we have one of our classmates that represents "Alice" and other who is "Bob", I will be "Eve".

Here is the screenshot from Facebook where my classmates published the p, g, X, Y, and I need to get the x and y, and then a key k.


I did the hack manually in my notebook, here is a capture.


If you check in the image, I started doing divisions only changing the dividend per a potency of 10 with n, where n start with one and increment in each division, when I finish the fourth division I noticed that in the dividend is only necessary to add a zero, so I did a big division, in the right of the paper I wrote a table, and in the first column I put the number of n, that represents x and y, and the second column is the result of (10^n)mod(19).

When I tried the potency of 17 and 18, I found the same X and Y that my classmates wrote in the publication in Facebook, so I check if the two numbers, one for x, and the other for y, give me the same key k.

I get x=17, y=18 and k=1.

Then I posted the x, y and the k, in a comment in the same post, and my classmates, verify if I was correct, and yes, I was correct.

After that, I did a program that do the same thing that I did manually, isn't a method that found the key when someone use this protocol, is only a sequential program that increment x and y, and verify if are the correct values for get the correct key.

Here is the code:


An example of the execution in the terminal, with the same p, g, X, Y, of the example that I did manually.


I get the same x, y, and the k, that I found doing it manually, so it seems to work well.

References:
[1] - Diffie-Hellman Protocol

30 de agosto de 2012

Analysis for Pseudorandomness in One-Time Keys

Seguridad de la Información y Criptografía
Homework 2

Last week we write a python program for create one-time pads for two users, and then we use one of the keys and send a encrypted message, and the other user receive that message and decrypt with the same key, and every key that we use was deleted.

In that program we use a python random function for create the one-time keys, and now we need to check if the keys are secure.

And the question is:

Are one-time pads unbreakable?
"Yes. But only if used properly. A one-time pad must be truly random data and must be kept secure in order to be unbreakable." [1]

In class we learn three characteristics of a randomness key:
  • Unpredictable.
  • Uncompressible.
  • Unreproducible.

This three characteristics can be passed with a statistical test in the random keys, there are some tests that we can use, like Monobit Test, longest run of ones in a block, non overlapping template, and more.

In my case I use two tests that I had used in the past, monobit test and frequency block test, the next link is one of my publications in this blog, where I talk about statistical tests for pseudorandomness numbers.

Statistical tests for pseudorandomness numbers

I modify my last code for one-time pads, and in this case I add the functions for check every key with the two tests.

Note: I add a hashtag in the main function in the lines that encrypt and decrypt the message, because I only want to check the result of the test.

And here is my code:


And here is an example of an execution where I only request 4 keys, and every key was checked by the two tests.


If you check my code, in the part of the monobit test I need to change a character for a binary number (0 or 1), and in the frequency blocks I change the character for an int number.

Other important thing is that in the frecuency blocks, in my runnings ever gets a 1.0, but is because is use a little length of the key, if I change for 100000, the number change, but it takes more time for check every key.

One more thing that I used for check my one-time pads, is compressing the file with the keys and view the difference of size of the original file with the compressed file, and we can know how many is the percentage of compressing.

Pay attention in keys1 with keys1.tar.gz the compression is 16.95% less than the original, and keys22 with keys22.tar.gz the compression is the same, so if I create a file with more keys the percentage of compression don't change drastically.

ramon@pavilion:~/Documents/programas/criptologia/breakonetimepad$ ls -l
total 20672
-rwxr-xr-x 1 ramon ramon     3289 Aug 30 08:02 checkontimepad.py
-rw-rw-r-- 1 ramon ramon  1001000 Aug 30 08:05 keys1
-rw-rw-r-- 1 ramon ramon   831446 Aug 30 08:07 keys1.tar.gz
-rw-rw-r-- 1 ramon ramon  1001000 Aug 30 08:05 keys2
-rw-rw-r-- 1 ramon ramon 10010000 Aug 30 03:35 keys22
-rw-rw-r-- 1 ramon ramon  8313357 Aug 30 03:35 keys22.tar.gz

The percentage of compression isn't as bad as I think, so if the compression was more than 50%, someone can attack our keys easily, but isn't the case.

References and other pages:
[1] - One-time pad
Statistical Tests for Random Number Generators

23 de agosto de 2012

One-time Pads

Seguridad de la Información y Criptografía
Homework 1

This is the first homework for the cryptography class, and the topic is One-Time Pads. We make a program where we create two files with the same list of keys and a function to encrypt and decrypt a message or text with a size less or equal than the key.

At the end of this post I embed my complete code, but in the next part I try to explain how my code works.

What is an One-time pad?


"In cryptography, the one-time pad is a type of encryption which has been proven to be impossible to crack if used correctly. Each bit or character from the plaintext is encrypted by a modular addition with a bit or character from a secret random key of the same length as the plaintext, resulting in a ciphertext."

If the key is truly random, as large as or greater than the plaintext, never reused in whole or part, and kept secret, the ciphertext will be impossible to decrypt or break without knowing the key. So, the only bad thing about this method is if we don't be careful how the list of keys are saved or where, it can be insecure, but is better that the last time when we only encrypt a text rotating the alphabet or changing the position of the alphabet.

My code


First of all, I create a function where the program open two different files, "keys1" and "keys2", then choose a random number between 32 and 126, for convert that number into a ASCII char character, and write a line of characters with a length defined in the beginning of the code (KEY_SIZE).

def create_files_with_keys(n):
  file1 = open('keys1', 'w')
  file2 = open('keys2', 'w')

  for i in range(n):
    key = ''
    for j in range(KEY_SIZE):
      key = key + chr(int(random.uniform(32,126)))
    key = key + '\n'
    file1.write(key)
    file2.write(key)

  file1.close()
  file2.close()
In this image I show what happens when I run my program. In the main function I call to "create_files_with_keys(n)", and the files were created.


And in this case I only create 4 keys, that I defined in the beginning of the code with a global variable. Check that the same keys were written in the two files.


Now for encrypt a message I read line by line in the file with the keys and save it in an array, then write again the keys in the file less the first that we need to use for the encryption.

I use the module for encrypt the message. And for debug print the message, the current key, and the ciphertext.

def encrypt(message):
  keys_file = open('keys1', 'r')
  ciphertext = ''
  residue = []

  for line in keys_file:
    residue.append(line.strip('\n'))
  keys_file.close()

  keys_file = open('keys1', 'w')
  for i in range(len(residue)-1):
    line = residue[i+1] + '\n'
    keys_file.writelines(line)

  message = message.zfill(KEY_SIZE)
  alphabet = map(chr, range(32,126))

  for i in range(KEY_SIZE):
    suma = alphabet.index(message[i]) + alphabet.index(residue[0][i])
    mod = suma%94
    ciphertext = ciphertext + alphabet[mod]

  print 'Message to encrypt: ' + message
  print 'Key used to encrypt: ' + residue[0]
  print 'Message encrypted: ' + ciphertext
  return ciphertext
For this time I use the file "keys2" to get the first key and can decrypt the message.

For debug I print the ciphertext, the key used (it must be the same for encrypt), and the message decrypted.

def decrypt(ciphertext):
  keys_file = open('keys2', 'r')
  message = ''
  residue = []

  for line in keys_file:
    residue.append(line.strip('\n'))
  keys_file.close()

  keys_file = open('keys2', 'w')
  for i in range(len(residue)-1):
    line = residue[i+1] + '\n'
    keys_file.writelines(line)

  alphabet = map(chr, range(32,126))

  for i in range(KEY_SIZE):
    suma = alphabet.index(ciphertext[i]) - alphabet.index(residue[0][i])
    mod = suma%94
    message = message + alphabet[mod]

  print 'Message to decrypt: ' + ciphertext
  print 'Key used to decrypt: ' + residue[0]
  print 'Message decrypted: ' + message.lstrip('0')
  return message.lstrip('0')
And finally the main function, where I used the number of keys created in the files for receive the same quantity of messages to encrypt and decrypt.

def main():
  create_files_with_keys(N_KEYS)
  print '\n'
  for i in range(N_KEYS):
    message = raw_input('Write a message: ')
    print '\n'
    ciphertext = encrypt(message)
    print '\n'
    message = decrypt(ciphertext)
    print '\n'
  print '\n'
Here's an example of how I write a message, the message is encrypted, the key in one files is deleted, then send the message to the function for decrypt, use the first key in the other file, delete the key and decrypt the message.


Complete code



References
One-Time Pad - Definition

9 de agosto de 2012

Ciphertext

Seguridad de la Información y Criptografía
Agregado 1

In the cryptography class, we have to create a program that we can use to encrypt and decrypt a message, we must publish a ciphertext, that can be decrypted by our classmates, and I can try decrypt the ciphertext of someone else. The person who decrypts a messaje, earns one extra point.

Here's my ciphertext:

6mct1RlAct6mqUmN1RlAqUJQ5SqUjJ1RctFT1RlActIbCMlAweOI,hIbOIMX8CT0sOIbCMlAweOIlAXWOIlAbdwe8C.zIbhwIblAhwwelAivXWwe8C8CT0lA,h.zWD.z!s-PlA:7T0CMlAOIT0WDweCMlAweCMbdT0,h.zT0!sweCMlA8Cwe0,we!shwweCMlAT0MXT0,hT0OIhwIblAhwweCMhwwelAXWOIT0lA0,T0CMwelAIb,hXW!sMXT0PZlAv.T0OIlA!sIbiv8CT0hwIblACMXWlAbd8C.zsOwe8CT0lAWD.z,hMXIb8C.zT0lA,hIbOIMX8CT0lAwe!slAsOT0!sWDT0hwIblAa}sObdwe8C.zIblAKgT0!sT0,hMX.z,hIb-PlAGqXW8CT0OIMXwelA!sT0lA0,T0MXT0!s!sT0PZlA!sIbCMlAweCMbd.zT0CMlA8Cwe0,we!shwweCMlAv.T0OIlA,hIbOICMweivXW.zhwIblAT0bdIbhwwe8CT08CCMwelAhwwelA!sIbCMlAbd!sT0OIIbCMlACMwe,h8CweMXIbCMlAhwwe!slAT08CsOT0lAMXIbMXT0!slAVLlAhwweei.zOI.zMX.zWDT0lAhwwe!slAa}sObdwe8C.zIb3YlA!sT0lAqUCMMX8Cwe!s!sT0lAhwwelA!sT0lA7cXWwe8CMXwePZlAXWOIT0lAweCMMXT0,h.zIbOIlAweCMbdT0,h.zT0!slAT0,hIb8CT0LlT0hwT0lA,hIbOIlAbdIbMXweOI,h.zT0!slACMeiXW,h.zweOIMXwelAbdT08CT0lAhwweCMMX8CXW.z8ClAXWOIlAbd!sT0OIweMXT0lAweOIMXwe8CIb-PlA5Swe8CCMweivXW.zhwT0lAbdIb8ClA!sIbCMlACM.zOI.zweCMMX8CIbCMlAT0ivweOIMXweCMlAhwwe!slAa}sObdwe8C.zIbPZlA!sT0lAbd8C.zOI,hweCMT0lA:7we.zT0lAWDXWwe!sT0lAv.T0,h.zT0lACMXWlAbdT0MX8C.zT0lAT0lA0,Ib8ChwIblAhwwelACMXWlAOIT0WDwelAweCMbdT0,h.zT0!slA!s!sweWDT0OIhwIblA,hIbOICM.zivIblA!sIbCMlAbd!sT0OIIbCMlA8CIb0,T0hwIbCMlAd8XWwelAbdIbhw8CT0OIlACMT0!sWDT08ClAT0lACMXWlAbdXWwe0,!sIblAVLlAhwweWDIb!sWDwe8ClA!sT0lA!s.z0,we8CMXT0hwlAT0lA!sT0lAivT0!sT02V.zT0-P