Using: Curve25519-ECDH, SHA256-HMAC, AES256-CBC — [Link to the GitHub Project Repo]
tcpdump pcap
01:07:18.371915 IP 192.168.1.171.64115 > 31.170.162.63.80: Flags [P.], seq 258:712, ack 1, win 8192, length 454: HTTP mode=mesg&user=bob&rcpt=jon&mesg=key,31237969521267061265339920357754601118035663355449910125550985699827426505154,7903087581924324533759768883989441673564165222638106623548350836149345932721 -- 01:07:18.783449 IP 31.170.162.63.80 > 192.168.1.171.64116: Flags [P.], seq 1:353, ack 539, win 250, length 352: HTTP: HTTP/1.1 200 OK 1450084038.47668400.66932:bob:key,31237969521267061265339920357754601118035663355449910125550985699827426505154,7903087581924324533759768883989441673564165222638106623548350836149345932721 -- 01:07:19.547229 IP 192.168.1.171.64117 > 31.170.162.63.80: Flags [P.], seq 258:712, ack 1, win 8192, length 454: HTTP mode=mesg&user=jon&rcpt=bob&mesg=key,20845162869924781138108110300526986101524551329253196414272755241823588505763,3845740679180735844612211279137657051909097428357280103024866020367868787613 -- 01:07:20.637809 IP 31.170.162.63.80 > 192.168.1.171.64118: Flags [P.], seq 1:353, ack 539, win 250, length 352: HTTP: HTTP/1.1 200 OK 1450084039.65591500.56627:jon:key,20845162869924781138108110300526986101524551329253196414272755241823588505763,3845740679180735844612211279137657051909097428357280103024866020367868787613 -- 01:07:30.861632 IP 192.168.1.171.64123 > 31.170.162.63.80: Flags [P.], seq 258:672, ack 1, win 8192, length 414: HTTP mode=mesg&user=bob&rcpt=jon&mesg=msg,471776850.748092,8017053b9ea82e9d52e41052cc3518cd,8bd681694098a46a6ffbb01158672929d1fc5f3859f3fc5cc5030de8e4ed6d6e -- 01:07:33.788855 IP 31.170.162.63.80 > 192.168.1.171.64124: Flags [P.], seq 1:313, ack 539, win 250, length 312: HTTP: HTTP/1.1 200 OK 1450084050.96252100.73649:bob:msg,471776850.748092,8017053b9ea82e9d52e41052cc3518cd,8bd681694098a46a6ffbb01158672929d1fc5f3859f3fc5cc5030de8e4ed6d6e
/* c helper swift functions */ bnum *getx(ecc *e) { return e->x; } bnum *gety(ecc *e) { return e->y; } ecc *eccryp() { char *a = "486662", *b = "1", *p = "57896044618658097711785492504343953926634992332820282019728792003956564819949"; char *x = "9", *y = "43114425171068552920764898935933967039370386198203806730763910166200978582548"; bnum *t, *u, *v, *w; ecc *e; t = bndec(p); u = bninit(t->size); w = bndec(x); bncopy(w, u); bnfree(w); v = bninit(t->size); w = bndec(y); bncopy(w, v); bnfree(w); e = ecinit(bndec(a), bndec(b), t, u, v); return e; } bnum *bnrnd(int size) { FILE *f; bnum *r; r = bninit(size); f = fopen("/dev/urandom", "r"); fread(r->nums, sizeof(unsigned int), size - 1, f); fclose(f); r->leng = size; while ((r->leng > 1) && (r->nums[r->leng - 1] == 0)) { r->leng -= 1; } return r; } /* Curve25519: a=486662, b=1, p=2^255 - 19 ECC DH: o * (n * P) == onP == noP == n * (o * P) */ char *ecdh(ecc *e, const char *n) { char *r = (char *)n; bnum *m; ecc *f; if (r == NULL) { m = bnrnd((e->p)->size); r = bnstr(m); } else { m = bndec((char *)n); } f = ecdup(e); pmul(m, e, f); (f->x)->leng = min((f->x)->leng, (e->p)->size); bncopy(f->x, e->x); (f->y)->leng = min((f->y)->leng, (e->p)->size); bncopy(f->y, e->y); bnfree(m); ecfree(f); return r; } void setexy(ecc *e, const char *x, const char *y) { bnum *t; t = bndec((char *)x); t->leng = min(t->leng, (e->p)->size); bncopy(t, e->x); bnfree(t); t = bndec((char *)y); t->leng = min(t->leng, (e->p)->size); bncopy(t, e->y); bnfree(t); } char *shash(const char *m) { char *o = malloc(256); sha256 hobj; sha256init(&hobj); sha256update(&hobj, (unsigned char *)m, (unsigned int)strlen(m)); sha256final(&hobj, o); return o; } char *sencr(const char *i, const char *m, const char *k, int d) { int x, y, w, z = 0; unsigned long ilen = strlen(i), mlen = strlen(m), klen = strlen(k); unsigned char tmp[16], ivn[16], msg[16], key[256]; char *hex = "0123456789abcdef"; char *enc = malloc(3 * strlen(m)); bzero(key, 256); for (x = 0; ((x + 1) < 64) && ((x + 1) < klen); x += 2) { for (y = 0; y < 16; ++y) { if (k[x] == hex[y]) { key[x / 2] |= (y << 4); } if (k[x + 1] == hex[y]) { key[x / 2] |= y; } } } aes256keys(key); for (x = 0; x < 16; ++x) { ivn[x] = 0; if (x < ilen) { ivn[x] = i[x]; } } x = 0; while (x < mlen) { if (d == 0) { for (y = 0; y < 16; ++y) { msg[y] = 0; if (x < mlen) { msg[y] = m[x]; ++x; } msg[y] ^= ivn[y]; } } else { for (y = 0; y < 16; ++y) { msg[y] = 0; if ((x + 1) < mlen) { for (w = 0; w < 16; ++w) { if (m[x] == hex[w]) { msg[y] |= (w << 4); } if (m[x + 1] == hex[w]) { msg[y] |= w; } } x += 2; } tmp[y] = msg[y]; } } aes256core(msg, key, d); if (d == 0) { for (y = 0; y < 16; ++y) { enc[z] = hex[(msg[y] >> 4) & 0xf]; ++z; enc[z] = hex[msg[y] & 0xf]; ++z; ivn[y] = msg[y]; } } else { for (y = 0; y < 16; ++y) { enc[z] = (msg[y] ^ ivn[y]); ++z; ivn[y] = tmp[y]; } } } enc[z] = 0; return enc; } char *hmac(const char *m, const char *k) { int x, y, i, j, bs = 64; unsigned long mlen = strlen(m), klen = strlen(k); char *hex = "0123456789abcdef", *hmout = malloc(256); unsigned char key[bs], ipad[bs], opad[bs]; sha256 hobj; bzero(key, bs); for (x = 0; ((x + 1) < 64) && ((x + 1) < klen); x += 2) { for (y = 0; y < 16; ++y) { if (k[x] == hex[y]) { key[x / 2] |= (y << 4); } if (k[x + 1] == hex[y]) { key[x / 2] |= y; } } } for (x = 0; x < bs; ++x) { ipad[x] = (0x36 ^ key[x]); opad[x] = (0x5C ^ key[x]); } sha256init(&hobj); sha256update(&hobj, ipad, bs); sha256update(&hobj, (unsigned char *)m, (unsigned int)mlen); sha256final(&hobj, hmout); for (x = 0; x < 8; ++x) { for (y = 0; y < 4; ++y) { i = ((x * 4) + y); j = (24 - (y * 8)); key[i] = ((hobj.h[x] >> j) & 0xff); } } sha256init(&hobj); sha256update(&hobj, opad, bs); sha256update(&hobj, key, 32); sha256final(&hobj, hmout); return hmout; }
// // ViewController.swift // smsg // import UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { let userText: UITextField = UITextField(frame: CGRect(x: 10.00, y: 32.00, width: 200.00, height: 30.00)) let passText: UITextField = UITextField(frame: CGRect(x: 10.00, y: 64.00, width: 200.00, height: 30.00)) let authButn: UIButton = UIButton(frame: CGRect(x: 225.00, y: 64.00, width: 100.00, height: 30.00)) let frndText: UITextField = UITextField(frame: CGRect(x: 10.00, y: 96.00, width: 200.00, height: 30.00)) let frndButn: UIButton = UIButton(frame: CGRect(x: 225.00, y: 96.00, width: 100.00, height: 30.00)) let seckText: UILabel = UILabel(frame: CGRect(x: 10.00, y: 128.00, width: 300.00, height: 30.00)) var mesgList: [String] = ["line 1", "line 2", "line 3"] let mesgHist: UITableView = UITableView(frame: CGRect(x: 10.00, y: 160.00, width: 300.00, height: 120.00)) let mesgText: UITextView = UITextView(frame: CGRect(x: 10.00, y: 284.00, width: 200.00, height: 60.00)) let mesgButn: UIButton = UIButton(frame: CGRect(x: 225.00, y: 284.00, width: 100.00, height: 30.00)) let vers = "1.9.9.1" let serv = "http://smsg.site88.net" var authkey: String = "" var dhkey: String = "" var dhx: String = "" var dhy: String = "" var skey: String = "" var tkey: String = "" var ecobj = eccryp() func readReply(mode: Int, response: String) { if (response != "") { print("r>"+response) } if (response.characters.count > 5) { if (mode == 0) { self.authkey = response.substringWithRange(Range<String.Index>(start:response.startIndex.advancedBy(5), end:response.endIndex)) dispatch_async(dispatch_get_main_queue()) { self.seckText.text = (" " + self.authkey) } } else if (mode == 3) { let linelist = response.characters.split{$0 == "\n"}.map(String.init) for line in linelist { let readlist = line.characters.split{$0 == ":"}.map(String.init) if (readlist.count > 2) { let infolist = readlist[2].characters.split{$0 == ","}.map(String.init) if (infolist.count == 3) { if ((readlist[1] == frndText.text) && (infolist[0] == "key")) { if (self.dhkey == "") { self.dhkey = String.fromCString(ecdh(self.ecobj, nil))! self.dhx = String.fromCString(bnstr(getx(self.ecobj)))! self.dhy = String.fromCString(bnstr(gety(self.ecobj)))! self.sendMesg(1, mesg: self.dhx+","+self.dhy) } setexy(self.ecobj, infolist[1], infolist[2]) ecdh(self.ecobj, self.dhkey) let tdhx = String.fromCString(bnstr(getx(self.ecobj))) let tdhy = String.fromCString(bnstr(gety(self.ecobj))) print("d>"+tdhx!+","+tdhy!) self.skey = String.fromCString(shash(tdhx!+","+tdhy!))! self.tkey = String.fromCString(shash(self.skey))! print("k>"+self.skey+","+self.tkey) dispatch_async(dispatch_get_main_queue()) { self.seckText.text = (" " + self.skey) } } } else if (infolist.count == 4) { if ((readlist[1] == frndText.text) && (infolist[0] == "msg")) { let smac = String.fromCString(hmac(infolist[1]+","+infolist[2], self.tkey)) print("v>"+smac!+"=="+infolist[3]) if (smac == infolist[3]) { let smesg = String.fromCString(sencr(infolist[1], infolist[2], self.skey, 1)) self.mesgList.append(smesg!) dispatch_async(dispatch_get_main_queue()) { self.mesgHist.reloadData() } } } } } } } } } func sendMesg(mode: Int, mesg: String) { var postdata: String = "" if (mode == 0) { postdata = ("mode=auth&user="+self.userText.text!+"&pass="+self.passText.text!) } else if (mode == 1) { postdata = ("mode=mesg&user="+self.userText.text!+"&auth="+self.authkey+"&rcpt="+self.frndText.text!+"&mesg=key,"+mesg) } else if (mode == 2) { postdata = ("mode=mesg&user="+self.userText.text!+"&auth="+self.authkey+"&rcpt="+self.frndText.text!+"&mesg=msg,"+mesg) } else if (mode == 3) { postdata = ("mode=read&user="+self.userText.text!+"&auth="+self.authkey) } let request = NSMutableURLRequest(URL: NSURL(string: self.serv)!) request.HTTPMethod = "POST" request.HTTPBody = postdata.dataUsingEncoding(NSUTF8StringEncoding) let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in let reply = NSString(data: data!, encoding: NSUTF8StringEncoding) self.readReply(mode, response: reply as! String) } task.resume() } func butnPress(butn: UIButton) { if (butn.titleLabel?.text == "Login") { self.sendMesg(0, mesg: "") } if (butn.titleLabel?.text == "Add") { if (self.dhkey == "") { self.dhkey = String.fromCString(ecdh(self.ecobj, nil))! self.dhx = String.fromCString(bnstr(getx(self.ecobj)))! self.dhy = String.fromCString(bnstr(gety(self.ecobj)))! } self.sendMesg(1, mesg: self.dhx+","+self.dhy) } if (butn.titleLabel?.text == "Send") { if (self.skey != "") { let stime = String(NSDate.timeIntervalSinceReferenceDate()) let smesg = String.fromCString(sencr(stime, self.mesgText.text, self.skey, 0)) let smac = String.fromCString(hmac(stime+","+smesg!, self.tkey)) self.sendMesg(2, mesg: stime+","+smesg!+","+smac!) } } } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.mesgList.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell") cell.textLabel!.text = self.mesgList[indexPath.row] cell.textLabel!.font = cell.textLabel!.font.fontWithSize(10) return cell } func backFunc(timer: NSTimer) { self.sendMesg(3, mesg: "") } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. print("i>draw init") /* login elements */ let userPadd = UIView(frame: CGRectMake(0, 0, 5, self.userText.frame.size.height)) self.userText.leftView = userPadd self.userText.leftViewMode = UITextFieldViewMode.Always self.userText.layer.cornerRadius = 2.0 self.userText.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.userText.layer.borderWidth = 2.0 self.userText.autocorrectionType = UITextAutocorrectionType.No self.userText.autocapitalizationType = UITextAutocapitalizationType.None self.view.addSubview(self.userText) let passPadd = UIView(frame: CGRectMake(0, 0, 5, self.passText.frame.size.height)) self.passText.leftView = passPadd self.passText.leftViewMode = UITextFieldViewMode.Always self.passText.layer.cornerRadius = 2.0 self.passText.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.passText.layer.borderWidth = 2.0 self.passText.secureTextEntry = true self.view.addSubview(self.passText) self.authButn.layer.cornerRadius = 2.0 self.authButn.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.authButn.layer.borderWidth = 2.0 self.authButn.setTitle("Login", forState: UIControlState.Normal) self.authButn.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal) self.authButn.addTarget(self, action: "butnPress:", forControlEvents: UIControlEvents.TouchUpInside) self.view.addSubview(self.authButn) /* friend elements */ let frndPadd = UIView(frame: CGRectMake(0, 0, 5, self.userText.frame.size.height)) self.frndText.leftView = frndPadd self.frndText.leftViewMode = UITextFieldViewMode.Always self.frndText.layer.cornerRadius = 2.0 self.frndText.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.frndText.layer.borderWidth = 2.0 self.frndText.autocorrectionType = UITextAutocorrectionType.No self.frndText.autocapitalizationType = UITextAutocapitalizationType.None self.view.addSubview(self.frndText) self.frndButn.layer.cornerRadius = 2.0 self.frndButn.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.frndButn.layer.borderWidth = 2.0 self.frndButn.setTitle("Add", forState: UIControlState.Normal) self.frndButn.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal) self.frndButn.addTarget(self, action: "butnPress:", forControlEvents: UIControlEvents.TouchUpInside) self.view.addSubview(self.frndButn) self.seckText.layer.cornerRadius = 2.0 self.seckText.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.seckText.layer.borderWidth = 2.0 self.seckText.font = self.seckText.font.fontWithSize(8) self.seckText.text = (" v" + self.vers) self.view.addSubview(self.seckText) /* message elements */ self.mesgHist.layer.cornerRadius = 2.0 self.mesgHist.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.mesgHist.layer.borderWidth = 2.0 self.mesgHist.rowHeight = 20.0 self.mesgHist.delegate = self self.mesgHist.dataSource = self self.view.addSubview(self.mesgHist) self.mesgText.layer.cornerRadius = 2.0 self.mesgText.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.mesgText.layer.borderWidth = 2.0 self.mesgText.autocorrectionType = UITextAutocorrectionType.No self.mesgText.autocapitalizationType = UITextAutocapitalizationType.None self.mesgText.text = "message string" self.view.addSubview(self.mesgText) self.mesgButn.layer.cornerRadius = 2.0 self.mesgButn.layer.borderColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0).CGColor self.mesgButn.layer.borderWidth = 2.0 self.mesgButn.setTitle("Send", forState: UIControlState.Normal) self.mesgButn.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal) self.mesgButn.addTarget(self, action: "butnPress:", forControlEvents: UIControlEvents.TouchUpInside) self.view.addSubview(self.mesgButn) /* background reader */ NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "backFunc:", userInfo: nil, repeats: true) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }