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.
}
}