Update for vndr update
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
parent
b4dd9b4376
commit
dabcfdc5a6
3 changed files with 2143 additions and 0 deletions
171
vendor/golang.org/x/crypto/otr/libotr_test_helper.c
generated
vendored
Normal file
171
vendor/golang.org/x/crypto/otr/libotr_test_helper.c
generated
vendored
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This code can be compiled and used to test the otr package against libotr.
|
||||||
|
// See otr_test.go.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <proto.h>
|
||||||
|
#include <message.h>
|
||||||
|
|
||||||
|
static int g_session_established = 0;
|
||||||
|
|
||||||
|
OtrlPolicy policy(void *opdata, ConnContext *context) {
|
||||||
|
return OTRL_POLICY_ALWAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_logged_in(void *opdata, const char *accountname, const char *protocol, const char *recipient) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inject_message(void *opdata, const char *accountname, const char *protocol, const char *recipient, const char *message) {
|
||||||
|
printf("%s\n", message);
|
||||||
|
fflush(stdout);
|
||||||
|
fprintf(stderr, "libotr helper sent: %s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notify(void *opdata, OtrlNotifyLevel level, const char *accountname, const char *protocol, const char *username, const char *title, const char *primary, const char *secondary) {
|
||||||
|
fprintf(stderr, "NOTIFY: %s %s %s %s\n", username, title, primary, secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
int display_otr_message(void *opdata, const char *accountname, const char *protocol, const char *username, const char *msg) {
|
||||||
|
fprintf(stderr, "MESSAGE: %s %s\n", username, msg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_context_list(void *opdata) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *protocol_name(void *opdata, const char *protocol) {
|
||||||
|
return "PROTOCOL";
|
||||||
|
}
|
||||||
|
|
||||||
|
void protocol_name_free(void *opdata, const char *protocol_name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void new_fingerprint(void *opdata, OtrlUserState us, const char *accountname, const char *protocol, const char *username, unsigned char fingerprint[20]) {
|
||||||
|
fprintf(stderr, "NEW FINGERPRINT\n");
|
||||||
|
g_session_established = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_fingerprints(void *opdata) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void gone_secure(void *opdata, ConnContext *context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void gone_insecure(void *opdata, ConnContext *context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void still_secure(void *opdata, ConnContext *context, int is_reply) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_message(void *opdata, const char *message) {
|
||||||
|
fprintf(stderr, "MESSAGE: %s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
int max_message_size(void *opdata, ConnContext *context) {
|
||||||
|
return 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *account_name(void *opdata, const char *account, const char *protocol) {
|
||||||
|
return "ACCOUNT";
|
||||||
|
}
|
||||||
|
|
||||||
|
void account_name_free(void *opdata, const char *account_name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
OtrlMessageAppOps uiops = {
|
||||||
|
policy,
|
||||||
|
NULL,
|
||||||
|
is_logged_in,
|
||||||
|
inject_message,
|
||||||
|
notify,
|
||||||
|
display_otr_message,
|
||||||
|
update_context_list,
|
||||||
|
protocol_name,
|
||||||
|
protocol_name_free,
|
||||||
|
new_fingerprint,
|
||||||
|
write_fingerprints,
|
||||||
|
gone_secure,
|
||||||
|
gone_insecure,
|
||||||
|
still_secure,
|
||||||
|
log_message,
|
||||||
|
max_message_size,
|
||||||
|
account_name,
|
||||||
|
account_name_free,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char kPrivateKeyData[] = "(privkeys (account (name \"account\") (protocol proto) (private-key (dsa (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#) (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#) (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#) (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#) (x #14D0345A3562C480A039E3C72764F72D79043216#)))))\n";
|
||||||
|
|
||||||
|
int
|
||||||
|
main() {
|
||||||
|
OTRL_INIT;
|
||||||
|
|
||||||
|
// We have to write the private key information to a file because the libotr
|
||||||
|
// API demands a filename to read from.
|
||||||
|
const char *tmpdir = "/tmp";
|
||||||
|
if (getenv("TMP")) {
|
||||||
|
tmpdir = getenv("TMP");
|
||||||
|
}
|
||||||
|
|
||||||
|
char private_key_file[256];
|
||||||
|
snprintf(private_key_file, sizeof(private_key_file), "%s/libotr_test_helper_privatekeys-XXXXXX", tmpdir);
|
||||||
|
int fd = mkstemp(private_key_file);
|
||||||
|
if (fd == -1) {
|
||||||
|
perror("creating temp file");
|
||||||
|
}
|
||||||
|
write(fd, kPrivateKeyData, sizeof(kPrivateKeyData)-1);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
OtrlUserState userstate = otrl_userstate_create();
|
||||||
|
otrl_privkey_read(userstate, private_key_file);
|
||||||
|
unlink(private_key_file);
|
||||||
|
|
||||||
|
fprintf(stderr, "libotr helper started\n");
|
||||||
|
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
char* message = fgets(buf, sizeof(buf), stdin);
|
||||||
|
if (strlen(message) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
message[strlen(message) - 1] = 0;
|
||||||
|
fprintf(stderr, "libotr helper got: %s\n", message);
|
||||||
|
|
||||||
|
char *newmessage = NULL;
|
||||||
|
OtrlTLV *tlvs;
|
||||||
|
int ignore_message = otrl_message_receiving(userstate, &uiops, NULL, "account", "proto", "peer", message, &newmessage, &tlvs, NULL, NULL);
|
||||||
|
if (tlvs) {
|
||||||
|
otrl_tlv_free(tlvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newmessage != NULL) {
|
||||||
|
fprintf(stderr, "libotr got: %s\n", newmessage);
|
||||||
|
otrl_message_free(newmessage);
|
||||||
|
|
||||||
|
gcry_error_t err;
|
||||||
|
char *newmessage = NULL;
|
||||||
|
|
||||||
|
err = otrl_message_sending(userstate, &uiops, NULL, "account", "proto", "peer", "test message", NULL, &newmessage, NULL, NULL);
|
||||||
|
if (newmessage == NULL) {
|
||||||
|
fprintf(stderr, "libotr didn't encrypt message\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
write(1, newmessage, strlen(newmessage));
|
||||||
|
write(1, "\n", 1);
|
||||||
|
g_session_established = 0;
|
||||||
|
otrl_message_free(newmessage);
|
||||||
|
write(1, "?OTRv2?\n", 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
1400
vendor/golang.org/x/crypto/otr/otr.go
generated
vendored
Normal file
1400
vendor/golang.org/x/crypto/otr/otr.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
572
vendor/golang.org/x/crypto/otr/smp.go
generated
vendored
Normal file
572
vendor/golang.org/x/crypto/otr/smp.go
generated
vendored
Normal file
|
@ -0,0 +1,572 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file implements the Socialist Millionaires Protocol as described in
|
||||||
|
// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html. The protocol
|
||||||
|
// specification is required in order to understand this code and, where
|
||||||
|
// possible, the variable names in the code match up with the spec.
|
||||||
|
|
||||||
|
package otr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"errors"
|
||||||
|
"hash"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
type smpFailure string
|
||||||
|
|
||||||
|
func (s smpFailure) Error() string {
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
var smpFailureError = smpFailure("otr: SMP protocol failed")
|
||||||
|
var smpSecretMissingError = smpFailure("otr: mutual secret needed")
|
||||||
|
|
||||||
|
const smpVersion = 1
|
||||||
|
|
||||||
|
const (
|
||||||
|
smpState1 = iota
|
||||||
|
smpState2
|
||||||
|
smpState3
|
||||||
|
smpState4
|
||||||
|
)
|
||||||
|
|
||||||
|
type smpState struct {
|
||||||
|
state int
|
||||||
|
a2, a3, b2, b3, pb, qb *big.Int
|
||||||
|
g2a, g3a *big.Int
|
||||||
|
g2, g3 *big.Int
|
||||||
|
g3b, papb, qaqb, ra *big.Int
|
||||||
|
saved *tlv
|
||||||
|
secret *big.Int
|
||||||
|
question string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) startSMP(question string) (tlvs []tlv) {
|
||||||
|
if c.smp.state != smpState1 {
|
||||||
|
tlvs = append(tlvs, c.generateSMPAbort())
|
||||||
|
}
|
||||||
|
tlvs = append(tlvs, c.generateSMP1(question))
|
||||||
|
c.smp.question = ""
|
||||||
|
c.smp.state = smpState2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) resetSMP() {
|
||||||
|
c.smp.state = smpState1
|
||||||
|
c.smp.secret = nil
|
||||||
|
c.smp.question = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) processSMP(in tlv) (out tlv, complete bool, err error) {
|
||||||
|
data := in.data
|
||||||
|
|
||||||
|
switch in.typ {
|
||||||
|
case tlvTypeSMPAbort:
|
||||||
|
if c.smp.state != smpState1 {
|
||||||
|
err = smpFailureError
|
||||||
|
}
|
||||||
|
c.resetSMP()
|
||||||
|
return
|
||||||
|
case tlvTypeSMP1WithQuestion:
|
||||||
|
// We preprocess this into a SMP1 message.
|
||||||
|
nulPos := bytes.IndexByte(data, 0)
|
||||||
|
if nulPos == -1 {
|
||||||
|
err = errors.New("otr: SMP message with question didn't contain a NUL byte")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.smp.question = string(data[:nulPos])
|
||||||
|
data = data[nulPos+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
numMPIs, data, ok := getU32(data)
|
||||||
|
if !ok || numMPIs > 20 {
|
||||||
|
err = errors.New("otr: corrupt SMP message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mpis := make([]*big.Int, numMPIs)
|
||||||
|
for i := range mpis {
|
||||||
|
var ok bool
|
||||||
|
mpis[i], data, ok = getMPI(data)
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("otr: corrupt SMP message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch in.typ {
|
||||||
|
case tlvTypeSMP1, tlvTypeSMP1WithQuestion:
|
||||||
|
if c.smp.state != smpState1 {
|
||||||
|
c.resetSMP()
|
||||||
|
out = c.generateSMPAbort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.smp.secret == nil {
|
||||||
|
err = smpSecretMissingError
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = c.processSMP1(mpis); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.smp.state = smpState3
|
||||||
|
out = c.generateSMP2()
|
||||||
|
case tlvTypeSMP2:
|
||||||
|
if c.smp.state != smpState2 {
|
||||||
|
c.resetSMP()
|
||||||
|
out = c.generateSMPAbort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if out, err = c.processSMP2(mpis); err != nil {
|
||||||
|
out = c.generateSMPAbort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.smp.state = smpState4
|
||||||
|
case tlvTypeSMP3:
|
||||||
|
if c.smp.state != smpState3 {
|
||||||
|
c.resetSMP()
|
||||||
|
out = c.generateSMPAbort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if out, err = c.processSMP3(mpis); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.smp.state = smpState1
|
||||||
|
c.smp.secret = nil
|
||||||
|
complete = true
|
||||||
|
case tlvTypeSMP4:
|
||||||
|
if c.smp.state != smpState4 {
|
||||||
|
c.resetSMP()
|
||||||
|
out = c.generateSMPAbort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = c.processSMP4(mpis); err != nil {
|
||||||
|
out = c.generateSMPAbort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.smp.state = smpState1
|
||||||
|
c.smp.secret = nil
|
||||||
|
complete = true
|
||||||
|
default:
|
||||||
|
panic("unknown SMP message")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) calcSMPSecret(mutualSecret []byte, weStarted bool) {
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write([]byte{smpVersion})
|
||||||
|
if weStarted {
|
||||||
|
h.Write(c.PrivateKey.PublicKey.Fingerprint())
|
||||||
|
h.Write(c.TheirPublicKey.Fingerprint())
|
||||||
|
} else {
|
||||||
|
h.Write(c.TheirPublicKey.Fingerprint())
|
||||||
|
h.Write(c.PrivateKey.PublicKey.Fingerprint())
|
||||||
|
}
|
||||||
|
h.Write(c.SSID[:])
|
||||||
|
h.Write(mutualSecret)
|
||||||
|
c.smp.secret = new(big.Int).SetBytes(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) generateSMP1(question string) tlv {
|
||||||
|
var randBuf [16]byte
|
||||||
|
c.smp.a2 = c.randMPI(randBuf[:])
|
||||||
|
c.smp.a3 = c.randMPI(randBuf[:])
|
||||||
|
g2a := new(big.Int).Exp(g, c.smp.a2, p)
|
||||||
|
g3a := new(big.Int).Exp(g, c.smp.a3, p)
|
||||||
|
h := sha256.New()
|
||||||
|
|
||||||
|
r2 := c.randMPI(randBuf[:])
|
||||||
|
r := new(big.Int).Exp(g, r2, p)
|
||||||
|
c2 := new(big.Int).SetBytes(hashMPIs(h, 1, r))
|
||||||
|
d2 := new(big.Int).Mul(c.smp.a2, c2)
|
||||||
|
d2.Sub(r2, d2)
|
||||||
|
d2.Mod(d2, q)
|
||||||
|
if d2.Sign() < 0 {
|
||||||
|
d2.Add(d2, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
r3 := c.randMPI(randBuf[:])
|
||||||
|
r.Exp(g, r3, p)
|
||||||
|
c3 := new(big.Int).SetBytes(hashMPIs(h, 2, r))
|
||||||
|
d3 := new(big.Int).Mul(c.smp.a3, c3)
|
||||||
|
d3.Sub(r3, d3)
|
||||||
|
d3.Mod(d3, q)
|
||||||
|
if d3.Sign() < 0 {
|
||||||
|
d3.Add(d3, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret tlv
|
||||||
|
if len(question) > 0 {
|
||||||
|
ret.typ = tlvTypeSMP1WithQuestion
|
||||||
|
ret.data = append(ret.data, question...)
|
||||||
|
ret.data = append(ret.data, 0)
|
||||||
|
} else {
|
||||||
|
ret.typ = tlvTypeSMP1
|
||||||
|
}
|
||||||
|
ret.data = appendU32(ret.data, 6)
|
||||||
|
ret.data = appendMPIs(ret.data, g2a, c2, d2, g3a, c3, d3)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) processSMP1(mpis []*big.Int) error {
|
||||||
|
if len(mpis) != 6 {
|
||||||
|
return errors.New("otr: incorrect number of arguments in SMP1 message")
|
||||||
|
}
|
||||||
|
g2a := mpis[0]
|
||||||
|
c2 := mpis[1]
|
||||||
|
d2 := mpis[2]
|
||||||
|
g3a := mpis[3]
|
||||||
|
c3 := mpis[4]
|
||||||
|
d3 := mpis[5]
|
||||||
|
h := sha256.New()
|
||||||
|
|
||||||
|
r := new(big.Int).Exp(g, d2, p)
|
||||||
|
s := new(big.Int).Exp(g2a, c2, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
t := new(big.Int).SetBytes(hashMPIs(h, 1, r))
|
||||||
|
if c2.Cmp(t) != 0 {
|
||||||
|
return errors.New("otr: ZKP c2 incorrect in SMP1 message")
|
||||||
|
}
|
||||||
|
r.Exp(g, d3, p)
|
||||||
|
s.Exp(g3a, c3, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
t.SetBytes(hashMPIs(h, 2, r))
|
||||||
|
if c3.Cmp(t) != 0 {
|
||||||
|
return errors.New("otr: ZKP c3 incorrect in SMP1 message")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.smp.g2a = g2a
|
||||||
|
c.smp.g3a = g3a
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) generateSMP2() tlv {
|
||||||
|
var randBuf [16]byte
|
||||||
|
b2 := c.randMPI(randBuf[:])
|
||||||
|
c.smp.b3 = c.randMPI(randBuf[:])
|
||||||
|
r2 := c.randMPI(randBuf[:])
|
||||||
|
r3 := c.randMPI(randBuf[:])
|
||||||
|
r4 := c.randMPI(randBuf[:])
|
||||||
|
r5 := c.randMPI(randBuf[:])
|
||||||
|
r6 := c.randMPI(randBuf[:])
|
||||||
|
|
||||||
|
g2b := new(big.Int).Exp(g, b2, p)
|
||||||
|
g3b := new(big.Int).Exp(g, c.smp.b3, p)
|
||||||
|
|
||||||
|
r := new(big.Int).Exp(g, r2, p)
|
||||||
|
h := sha256.New()
|
||||||
|
c2 := new(big.Int).SetBytes(hashMPIs(h, 3, r))
|
||||||
|
d2 := new(big.Int).Mul(b2, c2)
|
||||||
|
d2.Sub(r2, d2)
|
||||||
|
d2.Mod(d2, q)
|
||||||
|
if d2.Sign() < 0 {
|
||||||
|
d2.Add(d2, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Exp(g, r3, p)
|
||||||
|
c3 := new(big.Int).SetBytes(hashMPIs(h, 4, r))
|
||||||
|
d3 := new(big.Int).Mul(c.smp.b3, c3)
|
||||||
|
d3.Sub(r3, d3)
|
||||||
|
d3.Mod(d3, q)
|
||||||
|
if d3.Sign() < 0 {
|
||||||
|
d3.Add(d3, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.smp.g2 = new(big.Int).Exp(c.smp.g2a, b2, p)
|
||||||
|
c.smp.g3 = new(big.Int).Exp(c.smp.g3a, c.smp.b3, p)
|
||||||
|
c.smp.pb = new(big.Int).Exp(c.smp.g3, r4, p)
|
||||||
|
c.smp.qb = new(big.Int).Exp(g, r4, p)
|
||||||
|
r.Exp(c.smp.g2, c.smp.secret, p)
|
||||||
|
c.smp.qb.Mul(c.smp.qb, r)
|
||||||
|
c.smp.qb.Mod(c.smp.qb, p)
|
||||||
|
|
||||||
|
s := new(big.Int)
|
||||||
|
s.Exp(c.smp.g2, r6, p)
|
||||||
|
r.Exp(g, r5, p)
|
||||||
|
s.Mul(r, s)
|
||||||
|
s.Mod(s, p)
|
||||||
|
r.Exp(c.smp.g3, r5, p)
|
||||||
|
cp := new(big.Int).SetBytes(hashMPIs(h, 5, r, s))
|
||||||
|
|
||||||
|
// D5 = r5 - r4 cP mod q and D6 = r6 - y cP mod q
|
||||||
|
|
||||||
|
s.Mul(r4, cp)
|
||||||
|
r.Sub(r5, s)
|
||||||
|
d5 := new(big.Int).Mod(r, q)
|
||||||
|
if d5.Sign() < 0 {
|
||||||
|
d5.Add(d5, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Mul(c.smp.secret, cp)
|
||||||
|
r.Sub(r6, s)
|
||||||
|
d6 := new(big.Int).Mod(r, q)
|
||||||
|
if d6.Sign() < 0 {
|
||||||
|
d6.Add(d6, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret tlv
|
||||||
|
ret.typ = tlvTypeSMP2
|
||||||
|
ret.data = appendU32(ret.data, 11)
|
||||||
|
ret.data = appendMPIs(ret.data, g2b, c2, d2, g3b, c3, d3, c.smp.pb, c.smp.qb, cp, d5, d6)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) processSMP2(mpis []*big.Int) (out tlv, err error) {
|
||||||
|
if len(mpis) != 11 {
|
||||||
|
err = errors.New("otr: incorrect number of arguments in SMP2 message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g2b := mpis[0]
|
||||||
|
c2 := mpis[1]
|
||||||
|
d2 := mpis[2]
|
||||||
|
g3b := mpis[3]
|
||||||
|
c3 := mpis[4]
|
||||||
|
d3 := mpis[5]
|
||||||
|
pb := mpis[6]
|
||||||
|
qb := mpis[7]
|
||||||
|
cp := mpis[8]
|
||||||
|
d5 := mpis[9]
|
||||||
|
d6 := mpis[10]
|
||||||
|
h := sha256.New()
|
||||||
|
|
||||||
|
r := new(big.Int).Exp(g, d2, p)
|
||||||
|
s := new(big.Int).Exp(g2b, c2, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
s.SetBytes(hashMPIs(h, 3, r))
|
||||||
|
if c2.Cmp(s) != 0 {
|
||||||
|
err = errors.New("otr: ZKP c2 failed in SMP2 message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Exp(g, d3, p)
|
||||||
|
s.Exp(g3b, c3, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
s.SetBytes(hashMPIs(h, 4, r))
|
||||||
|
if c3.Cmp(s) != 0 {
|
||||||
|
err = errors.New("otr: ZKP c3 failed in SMP2 message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.smp.g2 = new(big.Int).Exp(g2b, c.smp.a2, p)
|
||||||
|
c.smp.g3 = new(big.Int).Exp(g3b, c.smp.a3, p)
|
||||||
|
|
||||||
|
r.Exp(g, d5, p)
|
||||||
|
s.Exp(c.smp.g2, d6, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
s.Exp(qb, cp, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
|
||||||
|
s.Exp(c.smp.g3, d5, p)
|
||||||
|
t := new(big.Int).Exp(pb, cp, p)
|
||||||
|
s.Mul(s, t)
|
||||||
|
s.Mod(s, p)
|
||||||
|
t.SetBytes(hashMPIs(h, 5, s, r))
|
||||||
|
if cp.Cmp(t) != 0 {
|
||||||
|
err = errors.New("otr: ZKP cP failed in SMP2 message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var randBuf [16]byte
|
||||||
|
r4 := c.randMPI(randBuf[:])
|
||||||
|
r5 := c.randMPI(randBuf[:])
|
||||||
|
r6 := c.randMPI(randBuf[:])
|
||||||
|
r7 := c.randMPI(randBuf[:])
|
||||||
|
|
||||||
|
pa := new(big.Int).Exp(c.smp.g3, r4, p)
|
||||||
|
r.Exp(c.smp.g2, c.smp.secret, p)
|
||||||
|
qa := new(big.Int).Exp(g, r4, p)
|
||||||
|
qa.Mul(qa, r)
|
||||||
|
qa.Mod(qa, p)
|
||||||
|
|
||||||
|
r.Exp(g, r5, p)
|
||||||
|
s.Exp(c.smp.g2, r6, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
|
||||||
|
s.Exp(c.smp.g3, r5, p)
|
||||||
|
cp.SetBytes(hashMPIs(h, 6, s, r))
|
||||||
|
|
||||||
|
r.Mul(r4, cp)
|
||||||
|
d5 = new(big.Int).Sub(r5, r)
|
||||||
|
d5.Mod(d5, q)
|
||||||
|
if d5.Sign() < 0 {
|
||||||
|
d5.Add(d5, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Mul(c.smp.secret, cp)
|
||||||
|
d6 = new(big.Int).Sub(r6, r)
|
||||||
|
d6.Mod(d6, q)
|
||||||
|
if d6.Sign() < 0 {
|
||||||
|
d6.Add(d6, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.ModInverse(qb, p)
|
||||||
|
qaqb := new(big.Int).Mul(qa, r)
|
||||||
|
qaqb.Mod(qaqb, p)
|
||||||
|
|
||||||
|
ra := new(big.Int).Exp(qaqb, c.smp.a3, p)
|
||||||
|
r.Exp(qaqb, r7, p)
|
||||||
|
s.Exp(g, r7, p)
|
||||||
|
cr := new(big.Int).SetBytes(hashMPIs(h, 7, s, r))
|
||||||
|
|
||||||
|
r.Mul(c.smp.a3, cr)
|
||||||
|
d7 := new(big.Int).Sub(r7, r)
|
||||||
|
d7.Mod(d7, q)
|
||||||
|
if d7.Sign() < 0 {
|
||||||
|
d7.Add(d7, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.smp.g3b = g3b
|
||||||
|
c.smp.qaqb = qaqb
|
||||||
|
|
||||||
|
r.ModInverse(pb, p)
|
||||||
|
c.smp.papb = new(big.Int).Mul(pa, r)
|
||||||
|
c.smp.papb.Mod(c.smp.papb, p)
|
||||||
|
c.smp.ra = ra
|
||||||
|
|
||||||
|
out.typ = tlvTypeSMP3
|
||||||
|
out.data = appendU32(out.data, 8)
|
||||||
|
out.data = appendMPIs(out.data, pa, qa, cp, d5, d6, ra, cr, d7)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) processSMP3(mpis []*big.Int) (out tlv, err error) {
|
||||||
|
if len(mpis) != 8 {
|
||||||
|
err = errors.New("otr: incorrect number of arguments in SMP3 message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pa := mpis[0]
|
||||||
|
qa := mpis[1]
|
||||||
|
cp := mpis[2]
|
||||||
|
d5 := mpis[3]
|
||||||
|
d6 := mpis[4]
|
||||||
|
ra := mpis[5]
|
||||||
|
cr := mpis[6]
|
||||||
|
d7 := mpis[7]
|
||||||
|
h := sha256.New()
|
||||||
|
|
||||||
|
r := new(big.Int).Exp(g, d5, p)
|
||||||
|
s := new(big.Int).Exp(c.smp.g2, d6, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
s.Exp(qa, cp, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
|
||||||
|
s.Exp(c.smp.g3, d5, p)
|
||||||
|
t := new(big.Int).Exp(pa, cp, p)
|
||||||
|
s.Mul(s, t)
|
||||||
|
s.Mod(s, p)
|
||||||
|
t.SetBytes(hashMPIs(h, 6, s, r))
|
||||||
|
if t.Cmp(cp) != 0 {
|
||||||
|
err = errors.New("otr: ZKP cP failed in SMP3 message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.ModInverse(c.smp.qb, p)
|
||||||
|
qaqb := new(big.Int).Mul(qa, r)
|
||||||
|
qaqb.Mod(qaqb, p)
|
||||||
|
|
||||||
|
r.Exp(qaqb, d7, p)
|
||||||
|
s.Exp(ra, cr, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
|
||||||
|
s.Exp(g, d7, p)
|
||||||
|
t.Exp(c.smp.g3a, cr, p)
|
||||||
|
s.Mul(s, t)
|
||||||
|
s.Mod(s, p)
|
||||||
|
t.SetBytes(hashMPIs(h, 7, s, r))
|
||||||
|
if t.Cmp(cr) != 0 {
|
||||||
|
err = errors.New("otr: ZKP cR failed in SMP3 message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var randBuf [16]byte
|
||||||
|
r7 := c.randMPI(randBuf[:])
|
||||||
|
rb := new(big.Int).Exp(qaqb, c.smp.b3, p)
|
||||||
|
|
||||||
|
r.Exp(qaqb, r7, p)
|
||||||
|
s.Exp(g, r7, p)
|
||||||
|
cr = new(big.Int).SetBytes(hashMPIs(h, 8, s, r))
|
||||||
|
|
||||||
|
r.Mul(c.smp.b3, cr)
|
||||||
|
d7 = new(big.Int).Sub(r7, r)
|
||||||
|
d7.Mod(d7, q)
|
||||||
|
if d7.Sign() < 0 {
|
||||||
|
d7.Add(d7, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
out.typ = tlvTypeSMP4
|
||||||
|
out.data = appendU32(out.data, 3)
|
||||||
|
out.data = appendMPIs(out.data, rb, cr, d7)
|
||||||
|
|
||||||
|
r.ModInverse(c.smp.pb, p)
|
||||||
|
r.Mul(pa, r)
|
||||||
|
r.Mod(r, p)
|
||||||
|
s.Exp(ra, c.smp.b3, p)
|
||||||
|
if r.Cmp(s) != 0 {
|
||||||
|
err = smpFailureError
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) processSMP4(mpis []*big.Int) error {
|
||||||
|
if len(mpis) != 3 {
|
||||||
|
return errors.New("otr: incorrect number of arguments in SMP4 message")
|
||||||
|
}
|
||||||
|
rb := mpis[0]
|
||||||
|
cr := mpis[1]
|
||||||
|
d7 := mpis[2]
|
||||||
|
h := sha256.New()
|
||||||
|
|
||||||
|
r := new(big.Int).Exp(c.smp.qaqb, d7, p)
|
||||||
|
s := new(big.Int).Exp(rb, cr, p)
|
||||||
|
r.Mul(r, s)
|
||||||
|
r.Mod(r, p)
|
||||||
|
|
||||||
|
s.Exp(g, d7, p)
|
||||||
|
t := new(big.Int).Exp(c.smp.g3b, cr, p)
|
||||||
|
s.Mul(s, t)
|
||||||
|
s.Mod(s, p)
|
||||||
|
t.SetBytes(hashMPIs(h, 8, s, r))
|
||||||
|
if t.Cmp(cr) != 0 {
|
||||||
|
return errors.New("otr: ZKP cR failed in SMP4 message")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Exp(rb, c.smp.a3, p)
|
||||||
|
if r.Cmp(c.smp.papb) != 0 {
|
||||||
|
return smpFailureError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conversation) generateSMPAbort() tlv {
|
||||||
|
return tlv{typ: tlvTypeSMPAbort}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashMPIs(h hash.Hash, magic byte, mpis ...*big.Int) []byte {
|
||||||
|
if h != nil {
|
||||||
|
h.Reset()
|
||||||
|
} else {
|
||||||
|
h = sha256.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Write([]byte{magic})
|
||||||
|
for _, mpi := range mpis {
|
||||||
|
h.Write(appendMPI(nil, mpi))
|
||||||
|
}
|
||||||
|
return h.Sum(nil)
|
||||||
|
}
|
Loading…
Reference in a new issue