(* RSA Library *)

(* Convert and ASCII string to an Integer *)
MessagesToIntegers[message_,N_]:=IntegerDigits[Fold[#1 256 + #2&, 0, ToCharacterCode[message]],N];

(* Interpret and integer as an ASCII string *)
IntegersToMessage[x_]:= FromCharacterCode[IntegerDigits[ x, 256]];

(* NOT NECESSARY FOR HOMEWORK 
  Code to Check the Signature of a Message
  Input 1: Integers to "unsign"
 Input 2: N = pq
  Input 3: Public Key e
  Output: Signed Message (interpreted as a string)
*)
UnsignMessageString[list_,N_,e_]:=FromCharacterCode[IntegerDigits[Fold[#1  N + #2&,0,Function[x, PowerMod[x,e,N]]/@ list],256]];

(* Code to Check the Signature of a Message
  Input 1: Integers to "unsign"
 Input 2: N = pq
  Input 3: Public Key e
  Output: Decrypted Message (interpreted as a string)
*)
DecryptMessageString[list_,N_,d_]:=FromCharacterCode[IntegerDigits[Fold[#1  N + #2&,0,Function[x, PowerMod[x,d,N]]/@ list],256]];

(* NOT NECESSARY FOR HOMEWORK
Code to Sign a Message
  Input 1: Strings/Messages to encrypt
 Input 2: N = pq
  Input 3: Private Key d
  Output: Signed Message (Integer)
*)
SignMessageString[message_,N_, d_]:= Function[x,PowerMod[x,d,N]] /@IntegerDigits[Fold[#1 256 + #2&, 0, ToCharacterCode[message]],N];

(* Code to Sign a Message
  Input 1: Strings/Messages to encrypt
 Input 2: N = pq
  Input 3: Public Key e
  Output: Encrypted Message (Integer)
*)
EncryptMessageString[message_,N_, e_]:= Function[x,PowerMod[x,e,N]] /@IntegerDigits[Fold[#1 256 + #2&, 0, ToCharacterCode[message]],N];

(* Encrpyt Messages 
	Input: MessageList - a set of integers to encrypt, N, e
     Output: A set of encrypted messages (integers)
*)
EncryptIntegers[messageList_,N_,e_]:=
	Function[x, PowerMod[x,e,N]]/@ messageList;

(* Input: Encrypted Messages (integer)
 Output: Set of decrypted Messages (viewed as an integers)
*)

DecryptInteger[encryptList_,N_,d_]:=Function[x, PowerMod[x,d,N]]/@ encryptList;

(* End of RSA Library *)

(* Example RSA Key -- This is purely for practice --does not match any actual RSA key from the problem *)
p = ;
q = ;

(* Trust Us They are prime! *)

N' = p q
t = (p-1)(q-1);
d = PowerMod[3,-1,t];
e = 3;

enc = EncryptMessageString["This is a test------------------------...............BEEP BEEP BEEP BEEP BEEP BEEP BEEP BEEP BEEP",N',e]

DecryptMessageString[enc,N',d]

EncryptIntegers[{42},N',e]

DecryptInteger[{74088},N',d]

x = ;
encPractice =First[EncryptIntegers[{},N',e]];

(* Feel free to experiment, in particular you should use this RSA key to sanity check your approach in problem E 
*)

(* END PRACTICE *)

(* Problem B *)

(Subscript[N, h])= ;
(Subscript[e, h]) = 7;
(Subscript[phi, h])= ;

(* Goal: Find (Subscript[p, h]) and (Subscript[q, h]) the prime factors of (Subscript[N, h])*)

(* Problem C *)
(Subscript[N, h'])=;

(Subscript[y, h'])= (Subscript[N, h'])-1;
(Subscript[x, h']) = ;

(* Sanity Check *)
Mod[(Subscript[x, h'  ])-(Subscript[y, h']),(Subscript[N, h'])] ≠ 0
Mod[((Subscript[y, h'])^2)- ((Subscript[x, h'])^2),(Subscript[N, h'])] == 0

(* Problem D *)

(* Public Key 1*)
e1 = 3;
N1 = ;

(* Encrypted Message m^e mod N *)
(* enc1 = *)
enc1 = {}

(* Public Key 2 *)
e2 = 3;
N2 = ;

(* Encrypted Message m^e mod N *)
enc2 = {};

(* Public Key 3 *)
e3 = 3;
N3 =;

(* Encrypted Message m^e mod N *)
enc3 = {}

(* Problem E *)
(* We reuse the key {N1,e} from part D. The encrypted message is encTrans.
  *)

encTrans = {};

(* encTrans = EncryptMessageString["Subject: Transfer Money to CMU Student, Name: Bill Gates.  My authorization code is *******. Please transfer the following ammount (dollars): d" ,N1,e]; *)
First[IntegersToMessage[{100}]]

(* So Bill Gates is offering to transfer 100 dollars.  Note: ******* is not the actual authentication code.   *)

encTransNew = encTrans;

(* Your goal is to generate encTransNew such that the following value is as high as possible, you should use the practice RSA keys to sanity check your solutions *)

(* Assuming that the authorization code is legitimate, this is how the bank determines how much money to give you, you cannot execute this code yourself because you don't have d1, however, you can try a similar experiments with the practice key N, d *)
A = First[MessagesToIntegers[Last[StringSplit[First[DecryptMessageString[{encTransNew},N1,d1]]," (dollars): "] ], N1]];If[A > 7000000, A = 0, A]

(* Bonus Problem! *)

enc  = ;
(* Note: 
   m1 = Fold[#1 256 + #2&, 0,ToCharacterCode[msg ]];
     enc = EncryptIntegers[m1,N1,e1]
 *)
msg' = "To get the bonus points all you need to do is get the password at the end of this message. This will be tough to do! Extra message here just to pad the length...... The password is: *********";
m2=Fold[#1 256 + #2&, 0,ToCharacterCode[msg']];
enc'= EncryptIntegers[m1,N1,e1];
(* Of course ********* is not the real password.  The real password is an ASCII string with 9 characters.  Your goal: Find the password! *)

(* As a hint m2 may be helpful somehow... *)