Browse code

Bump vndr

We can do that now as we're no longer carrying archive/tar.
Note that latest vndr removes vendor/ subdir so we don't have to,
thus the change in hack/validate/vendor.

While at it, re-run a new vndr version to make sure everything
that should be there is.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>

Kir Kolyshkin authored on 2018/08/29 04:53:33
Showing 19 changed files
... ...
@@ -1,6 +1,6 @@
1 1
 #!/bin/sh
2 2
 
3
-VNDR_COMMIT=a6e196d8b4b0cbbdc29aebdb20c59ac6926bb384
3
+VNDR_COMMIT=81cb8916aad3c8d06193f008dba3e16f82851f52
4 4
 
5 5
 install_vndr() {
6 6
 	echo "Install vndr version $VNDR_COMMIT"
... ...
@@ -9,10 +9,7 @@ validate_vendor_diff(){
9 9
 	unset IFS
10 10
 
11 11
 	if [ ${#files[@]} -gt 0 ]; then
12
-		# Remove vendor/ first so  that anything not included in vendor.conf will
13
-		# cause the validation to fail.
14
-		ls -d vendor/* | xargs rm -rf
15
-		# run vndr to recreate vendor/
12
+		# recreate vendor/
16 13
 		vndr
17 14
 		# check if any files have changed
18 15
 		diffs="$(git status --porcelain -- vendor 2>/dev/null)"
19 16
new file mode 100644
... ...
@@ -0,0 +1,197 @@
0
+// Copyright 2012 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// This code can be compiled and used to test the otr package against libotr.
5
+// See otr_test.go.
6
+
7
+// +build ignore
8
+
9
+#include <stdio.h>
10
+#include <stdlib.h>
11
+#include <unistd.h>
12
+
13
+#include <proto.h>
14
+#include <message.h>
15
+#include <privkey.h>
16
+
17
+static int g_session_established = 0;
18
+
19
+OtrlPolicy policy(void *opdata, ConnContext *context) {
20
+  return OTRL_POLICY_ALWAYS;
21
+}
22
+
23
+int is_logged_in(void *opdata, const char *accountname, const char *protocol,
24
+                 const char *recipient) {
25
+  return 1;
26
+}
27
+
28
+void inject_message(void *opdata, const char *accountname, const char *protocol,
29
+                    const char *recipient, const char *message) {
30
+  printf("%s\n", message);
31
+  fflush(stdout);
32
+  fprintf(stderr, "libotr helper sent: %s\n", message);
33
+}
34
+
35
+void update_context_list(void *opdata) {}
36
+
37
+void new_fingerprint(void *opdata, OtrlUserState us, const char *accountname,
38
+                     const char *protocol, const char *username,
39
+                     unsigned char fingerprint[20]) {
40
+  fprintf(stderr, "NEW FINGERPRINT\n");
41
+  g_session_established = 1;
42
+}
43
+
44
+void write_fingerprints(void *opdata) {}
45
+
46
+void gone_secure(void *opdata, ConnContext *context) {}
47
+
48
+void gone_insecure(void *opdata, ConnContext *context) {}
49
+
50
+void still_secure(void *opdata, ConnContext *context, int is_reply) {}
51
+
52
+int max_message_size(void *opdata, ConnContext *context) { return 99999; }
53
+
54
+const char *account_name(void *opdata, const char *account,
55
+                         const char *protocol) {
56
+  return "ACCOUNT";
57
+}
58
+
59
+void account_name_free(void *opdata, const char *account_name) {}
60
+
61
+const char *error_message(void *opdata, ConnContext *context,
62
+                          OtrlErrorCode err_code) {
63
+  return "ERR";
64
+}
65
+
66
+void error_message_free(void *opdata, const char *msg) {}
67
+
68
+void resent_msg_prefix_free(void *opdata, const char *prefix) {}
69
+
70
+void handle_smp_event(void *opdata, OtrlSMPEvent smp_event,
71
+                      ConnContext *context, unsigned short progress_event,
72
+                      char *question) {}
73
+
74
+void handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
75
+                      ConnContext *context, const char *message,
76
+                      gcry_error_t err) {
77
+  fprintf(stderr, "msg event: %d %s\n", msg_event, message);
78
+}
79
+
80
+OtrlMessageAppOps uiops = {
81
+    policy,
82
+    NULL,
83
+    is_logged_in,
84
+    inject_message,
85
+    update_context_list,
86
+    new_fingerprint,
87
+    write_fingerprints,
88
+    gone_secure,
89
+    gone_insecure,
90
+    still_secure,
91
+    max_message_size,
92
+    account_name,
93
+    account_name_free,
94
+    NULL, /* received_symkey */
95
+    error_message,
96
+    error_message_free,
97
+    NULL, /* resent_msg_prefix */
98
+    resent_msg_prefix_free,
99
+    handle_smp_event,
100
+    handle_msg_event,
101
+    NULL /* create_instag */,
102
+    NULL /* convert_msg */,
103
+    NULL /* convert_free */,
104
+    NULL /* timer_control */,
105
+};
106
+
107
+static const char kPrivateKeyData[] =
108
+    "(privkeys (account (name \"account\") (protocol proto) (private-key (dsa "
109
+    "(p "
110
+    "#00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F"
111
+    "30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E"
112
+    "5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB"
113
+    "8C031D3561FECEE72EBB4A090D450A9B7A857#) (q "
114
+    "#00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#) (g "
115
+    "#535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F"
116
+    "1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F"
117
+    "6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57"
118
+    "597766A2F9CE3857D7ACE3E1E3BC1FC6F26#) (y "
119
+    "#0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF"
120
+    "2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93"
121
+    "454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A"
122
+    "3C0FF501E3DC673B76D7BABF349009B6ECF#) (x "
123
+    "#14D0345A3562C480A039E3C72764F72D79043216#)))))\n";
124
+
125
+int main() {
126
+  OTRL_INIT;
127
+
128
+  // We have to write the private key information to a file because the libotr
129
+  // API demands a filename to read from.
130
+  const char *tmpdir = "/tmp";
131
+  if (getenv("TMP")) {
132
+    tmpdir = getenv("TMP");
133
+  }
134
+
135
+  char private_key_file[256];
136
+  snprintf(private_key_file, sizeof(private_key_file),
137
+           "%s/libotr_test_helper_privatekeys-XXXXXX", tmpdir);
138
+  int fd = mkstemp(private_key_file);
139
+  if (fd == -1) {
140
+    perror("creating temp file");
141
+  }
142
+  write(fd, kPrivateKeyData, sizeof(kPrivateKeyData) - 1);
143
+  close(fd);
144
+
145
+  OtrlUserState userstate = otrl_userstate_create();
146
+  otrl_privkey_read(userstate, private_key_file);
147
+  unlink(private_key_file);
148
+
149
+  fprintf(stderr, "libotr helper started\n");
150
+
151
+  char buf[4096];
152
+
153
+  for (;;) {
154
+    char *message = fgets(buf, sizeof(buf), stdin);
155
+    if (strlen(message) == 0) {
156
+      break;
157
+    }
158
+    message[strlen(message) - 1] = 0;
159
+    fprintf(stderr, "libotr helper got: %s\n", message);
160
+
161
+    char *newmessage = NULL;
162
+    OtrlTLV *tlvs;
163
+    int ignore_message = otrl_message_receiving(
164
+        userstate, &uiops, NULL, "account", "proto", "peer", message,
165
+        &newmessage, &tlvs, NULL, NULL, NULL);
166
+    if (tlvs) {
167
+      otrl_tlv_free(tlvs);
168
+    }
169
+
170
+    if (newmessage != NULL) {
171
+      fprintf(stderr, "libotr got: %s\n", newmessage);
172
+      otrl_message_free(newmessage);
173
+
174
+      gcry_error_t err;
175
+      char *newmessage = NULL;
176
+
177
+      err = otrl_message_sending(userstate, &uiops, NULL, "account", "proto",
178
+                                 "peer", 0, "test message", NULL, &newmessage,
179
+                                 OTRL_FRAGMENT_SEND_SKIP, NULL, NULL, NULL);
180
+      if (newmessage == NULL) {
181
+        fprintf(stderr, "libotr didn't encrypt message\n");
182
+        return 1;
183
+      }
184
+      write(1, newmessage, strlen(newmessage));
185
+      write(1, "\n", 1);
186
+      fprintf(stderr, "libotr sent: %s\n", newmessage);
187
+      otrl_message_free(newmessage);
188
+
189
+      g_session_established = 0;
190
+      write(1, "?OTRv2?\n", 8);
191
+      fprintf(stderr, "libotr sent: ?OTRv2\n");
192
+    }
193
+  }
194
+
195
+  return 0;
196
+}
0 197
new file mode 100644
... ...
@@ -0,0 +1,1415 @@
0
+// Copyright 2012 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// Package otr implements the Off The Record protocol as specified in
5
+// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html
6
+package otr // import "golang.org/x/crypto/otr"
7
+
8
+import (
9
+	"bytes"
10
+	"crypto/aes"
11
+	"crypto/cipher"
12
+	"crypto/dsa"
13
+	"crypto/hmac"
14
+	"crypto/rand"
15
+	"crypto/sha1"
16
+	"crypto/sha256"
17
+	"crypto/subtle"
18
+	"encoding/base64"
19
+	"encoding/hex"
20
+	"errors"
21
+	"hash"
22
+	"io"
23
+	"math/big"
24
+	"strconv"
25
+)
26
+
27
+// SecurityChange describes a change in the security state of a Conversation.
28
+type SecurityChange int
29
+
30
+const (
31
+	NoChange SecurityChange = iota
32
+	// NewKeys indicates that a key exchange has completed. This occurs
33
+	// when a conversation first becomes encrypted, and when the keys are
34
+	// renegotiated within an encrypted conversation.
35
+	NewKeys
36
+	// SMPSecretNeeded indicates that the peer has started an
37
+	// authentication and that we need to supply a secret. Call SMPQuestion
38
+	// to get the optional, human readable challenge and then Authenticate
39
+	// to supply the matching secret.
40
+	SMPSecretNeeded
41
+	// SMPComplete indicates that an authentication completed. The identity
42
+	// of the peer has now been confirmed.
43
+	SMPComplete
44
+	// SMPFailed indicates that an authentication failed.
45
+	SMPFailed
46
+	// ConversationEnded indicates that the peer ended the secure
47
+	// conversation.
48
+	ConversationEnded
49
+)
50
+
51
+// QueryMessage can be sent to a peer to start an OTR conversation.
52
+var QueryMessage = "?OTRv2?"
53
+
54
+// ErrorPrefix can be used to make an OTR error by appending an error message
55
+// to it.
56
+var ErrorPrefix = "?OTR Error:"
57
+
58
+var (
59
+	fragmentPartSeparator = []byte(",")
60
+	fragmentPrefix        = []byte("?OTR,")
61
+	msgPrefix             = []byte("?OTR:")
62
+	queryMarker           = []byte("?OTR")
63
+)
64
+
65
+// isQuery attempts to parse an OTR query from msg and returns the greatest
66
+// common version, or 0 if msg is not an OTR query.
67
+func isQuery(msg []byte) (greatestCommonVersion int) {
68
+	pos := bytes.Index(msg, queryMarker)
69
+	if pos == -1 {
70
+		return 0
71
+	}
72
+	for i, c := range msg[pos+len(queryMarker):] {
73
+		if i == 0 {
74
+			if c == '?' {
75
+				// Indicates support for version 1, but we don't
76
+				// implement that.
77
+				continue
78
+			}
79
+
80
+			if c != 'v' {
81
+				// Invalid message
82
+				return 0
83
+			}
84
+
85
+			continue
86
+		}
87
+
88
+		if c == '?' {
89
+			// End of message
90
+			return
91
+		}
92
+
93
+		if c == ' ' || c == '\t' {
94
+			// Probably an invalid message
95
+			return 0
96
+		}
97
+
98
+		if c == '2' {
99
+			greatestCommonVersion = 2
100
+		}
101
+	}
102
+
103
+	return 0
104
+}
105
+
106
+const (
107
+	statePlaintext = iota
108
+	stateEncrypted
109
+	stateFinished
110
+)
111
+
112
+const (
113
+	authStateNone = iota
114
+	authStateAwaitingDHKey
115
+	authStateAwaitingRevealSig
116
+	authStateAwaitingSig
117
+)
118
+
119
+const (
120
+	msgTypeDHCommit  = 2
121
+	msgTypeData      = 3
122
+	msgTypeDHKey     = 10
123
+	msgTypeRevealSig = 17
124
+	msgTypeSig       = 18
125
+)
126
+
127
+const (
128
+	// If the requested fragment size is less than this, it will be ignored.
129
+	minFragmentSize = 18
130
+	// Messages are padded to a multiple of this number of bytes.
131
+	paddingGranularity = 256
132
+	// The number of bytes in a Diffie-Hellman private value (320-bits).
133
+	dhPrivateBytes = 40
134
+	// The number of bytes needed to represent an element of the DSA
135
+	// subgroup (160-bits).
136
+	dsaSubgroupBytes = 20
137
+	// The number of bytes of the MAC that are sent on the wire (160-bits).
138
+	macPrefixBytes = 20
139
+)
140
+
141
+// These are the global, common group parameters for OTR.
142
+var (
143
+	p       *big.Int // group prime
144
+	g       *big.Int // group generator
145
+	q       *big.Int // group order
146
+	pMinus2 *big.Int
147
+)
148
+
149
+func init() {
150
+	p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16)
151
+	q, _ = new(big.Int).SetString("7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68948127044533E63A0105DF531D89CD9128A5043CC71A026EF7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9EE1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AFC1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF", 16)
152
+	g = new(big.Int).SetInt64(2)
153
+	pMinus2 = new(big.Int).Sub(p, g)
154
+}
155
+
156
+// Conversation represents a relation with a peer. The zero value is a valid
157
+// Conversation, although PrivateKey must be set.
158
+//
159
+// When communicating with a peer, all inbound messages should be passed to
160
+// Conversation.Receive and all outbound messages to Conversation.Send. The
161
+// Conversation will take care of maintaining the encryption state and
162
+// negotiating encryption as needed.
163
+type Conversation struct {
164
+	// PrivateKey contains the private key to use to sign key exchanges.
165
+	PrivateKey *PrivateKey
166
+
167
+	// Rand can be set to override the entropy source. Otherwise,
168
+	// crypto/rand will be used.
169
+	Rand io.Reader
170
+	// If FragmentSize is set, all messages produced by Receive and Send
171
+	// will be fragmented into messages of, at most, this number of bytes.
172
+	FragmentSize int
173
+
174
+	// Once Receive has returned NewKeys once, the following fields are
175
+	// valid.
176
+	SSID           [8]byte
177
+	TheirPublicKey PublicKey
178
+
179
+	state, authState int
180
+
181
+	r       [16]byte
182
+	x, y    *big.Int
183
+	gx, gy  *big.Int
184
+	gxBytes []byte
185
+	digest  [sha256.Size]byte
186
+
187
+	revealKeys, sigKeys akeKeys
188
+
189
+	myKeyId         uint32
190
+	myCurrentDHPub  *big.Int
191
+	myCurrentDHPriv *big.Int
192
+	myLastDHPub     *big.Int
193
+	myLastDHPriv    *big.Int
194
+
195
+	theirKeyId        uint32
196
+	theirCurrentDHPub *big.Int
197
+	theirLastDHPub    *big.Int
198
+
199
+	keySlots [4]keySlot
200
+
201
+	myCounter    [8]byte
202
+	theirLastCtr [8]byte
203
+	oldMACs      []byte
204
+
205
+	k, n int // fragment state
206
+	frag []byte
207
+
208
+	smp smpState
209
+}
210
+
211
+// A keySlot contains key material for a specific (their keyid, my keyid) pair.
212
+type keySlot struct {
213
+	// used is true if this slot is valid. If false, it's free for reuse.
214
+	used                   bool
215
+	theirKeyId             uint32
216
+	myKeyId                uint32
217
+	sendAESKey, recvAESKey []byte
218
+	sendMACKey, recvMACKey []byte
219
+	theirLastCtr           [8]byte
220
+}
221
+
222
+// akeKeys are generated during key exchange. There's one set for the reveal
223
+// signature message and another for the signature message. In the protocol
224
+// spec the latter are indicated with a prime mark.
225
+type akeKeys struct {
226
+	c      [16]byte
227
+	m1, m2 [32]byte
228
+}
229
+
230
+func (c *Conversation) rand() io.Reader {
231
+	if c.Rand != nil {
232
+		return c.Rand
233
+	}
234
+	return rand.Reader
235
+}
236
+
237
+func (c *Conversation) randMPI(buf []byte) *big.Int {
238
+	_, err := io.ReadFull(c.rand(), buf)
239
+	if err != nil {
240
+		panic("otr: short read from random source")
241
+	}
242
+
243
+	return new(big.Int).SetBytes(buf)
244
+}
245
+
246
+// tlv represents the type-length value from the protocol.
247
+type tlv struct {
248
+	typ, length uint16
249
+	data        []byte
250
+}
251
+
252
+const (
253
+	tlvTypePadding          = 0
254
+	tlvTypeDisconnected     = 1
255
+	tlvTypeSMP1             = 2
256
+	tlvTypeSMP2             = 3
257
+	tlvTypeSMP3             = 4
258
+	tlvTypeSMP4             = 5
259
+	tlvTypeSMPAbort         = 6
260
+	tlvTypeSMP1WithQuestion = 7
261
+)
262
+
263
+// Receive handles a message from a peer. It returns a human readable message,
264
+// an indicator of whether that message was encrypted, a hint about the
265
+// encryption state and zero or more messages to send back to the peer.
266
+// These messages do not need to be passed to Send before transmission.
267
+func (c *Conversation) Receive(in []byte) (out []byte, encrypted bool, change SecurityChange, toSend [][]byte, err error) {
268
+	if bytes.HasPrefix(in, fragmentPrefix) {
269
+		in, err = c.processFragment(in)
270
+		if in == nil || err != nil {
271
+			return
272
+		}
273
+	}
274
+
275
+	if bytes.HasPrefix(in, msgPrefix) && in[len(in)-1] == '.' {
276
+		in = in[len(msgPrefix) : len(in)-1]
277
+	} else if version := isQuery(in); version > 0 {
278
+		c.authState = authStateAwaitingDHKey
279
+		c.reset()
280
+		toSend = c.encode(c.generateDHCommit())
281
+		return
282
+	} else {
283
+		// plaintext message
284
+		out = in
285
+		return
286
+	}
287
+
288
+	msg := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
289
+	msgLen, err := base64.StdEncoding.Decode(msg, in)
290
+	if err != nil {
291
+		err = errors.New("otr: invalid base64 encoding in message")
292
+		return
293
+	}
294
+	msg = msg[:msgLen]
295
+
296
+	// The first two bytes are the protocol version (2)
297
+	if len(msg) < 3 || msg[0] != 0 || msg[1] != 2 {
298
+		err = errors.New("otr: invalid OTR message")
299
+		return
300
+	}
301
+
302
+	msgType := int(msg[2])
303
+	msg = msg[3:]
304
+
305
+	switch msgType {
306
+	case msgTypeDHCommit:
307
+		switch c.authState {
308
+		case authStateNone:
309
+			c.authState = authStateAwaitingRevealSig
310
+			if err = c.processDHCommit(msg); err != nil {
311
+				return
312
+			}
313
+			c.reset()
314
+			toSend = c.encode(c.generateDHKey())
315
+			return
316
+		case authStateAwaitingDHKey:
317
+			// This is a 'SYN-crossing'. The greater digest wins.
318
+			var cmp int
319
+			if cmp, err = c.compareToDHCommit(msg); err != nil {
320
+				return
321
+			}
322
+			if cmp > 0 {
323
+				// We win. Retransmit DH commit.
324
+				toSend = c.encode(c.serializeDHCommit())
325
+				return
326
+			} else {
327
+				// They win. We forget about our DH commit.
328
+				c.authState = authStateAwaitingRevealSig
329
+				if err = c.processDHCommit(msg); err != nil {
330
+					return
331
+				}
332
+				c.reset()
333
+				toSend = c.encode(c.generateDHKey())
334
+				return
335
+			}
336
+		case authStateAwaitingRevealSig:
337
+			if err = c.processDHCommit(msg); err != nil {
338
+				return
339
+			}
340
+			toSend = c.encode(c.serializeDHKey())
341
+		case authStateAwaitingSig:
342
+			if err = c.processDHCommit(msg); err != nil {
343
+				return
344
+			}
345
+			c.reset()
346
+			toSend = c.encode(c.generateDHKey())
347
+			c.authState = authStateAwaitingRevealSig
348
+		default:
349
+			panic("bad state")
350
+		}
351
+	case msgTypeDHKey:
352
+		switch c.authState {
353
+		case authStateAwaitingDHKey:
354
+			var isSame bool
355
+			if isSame, err = c.processDHKey(msg); err != nil {
356
+				return
357
+			}
358
+			if isSame {
359
+				err = errors.New("otr: unexpected duplicate DH key")
360
+				return
361
+			}
362
+			toSend = c.encode(c.generateRevealSig())
363
+			c.authState = authStateAwaitingSig
364
+		case authStateAwaitingSig:
365
+			var isSame bool
366
+			if isSame, err = c.processDHKey(msg); err != nil {
367
+				return
368
+			}
369
+			if isSame {
370
+				toSend = c.encode(c.serializeDHKey())
371
+			}
372
+		}
373
+	case msgTypeRevealSig:
374
+		if c.authState != authStateAwaitingRevealSig {
375
+			return
376
+		}
377
+		if err = c.processRevealSig(msg); err != nil {
378
+			return
379
+		}
380
+		toSend = c.encode(c.generateSig())
381
+		c.authState = authStateNone
382
+		c.state = stateEncrypted
383
+		change = NewKeys
384
+	case msgTypeSig:
385
+		if c.authState != authStateAwaitingSig {
386
+			return
387
+		}
388
+		if err = c.processSig(msg); err != nil {
389
+			return
390
+		}
391
+		c.authState = authStateNone
392
+		c.state = stateEncrypted
393
+		change = NewKeys
394
+	case msgTypeData:
395
+		if c.state != stateEncrypted {
396
+			err = errors.New("otr: encrypted message received without encrypted session established")
397
+			return
398
+		}
399
+		var tlvs []tlv
400
+		out, tlvs, err = c.processData(msg)
401
+		encrypted = true
402
+
403
+	EachTLV:
404
+		for _, inTLV := range tlvs {
405
+			switch inTLV.typ {
406
+			case tlvTypeDisconnected:
407
+				change = ConversationEnded
408
+				c.state = stateFinished
409
+				break EachTLV
410
+			case tlvTypeSMP1, tlvTypeSMP2, tlvTypeSMP3, tlvTypeSMP4, tlvTypeSMPAbort, tlvTypeSMP1WithQuestion:
411
+				var reply tlv
412
+				var complete bool
413
+				reply, complete, err = c.processSMP(inTLV)
414
+				if err == smpSecretMissingError {
415
+					err = nil
416
+					change = SMPSecretNeeded
417
+					c.smp.saved = &inTLV
418
+					return
419
+				}
420
+				if err == smpFailureError {
421
+					err = nil
422
+					change = SMPFailed
423
+				} else if complete {
424
+					change = SMPComplete
425
+				}
426
+				if reply.typ != 0 {
427
+					toSend = c.encode(c.generateData(nil, &reply))
428
+				}
429
+				break EachTLV
430
+			default:
431
+				// skip unknown TLVs
432
+			}
433
+		}
434
+	default:
435
+		err = errors.New("otr: unknown message type " + strconv.Itoa(msgType))
436
+	}
437
+
438
+	return
439
+}
440
+
441
+// Send takes a human readable message from the local user, possibly encrypts
442
+// it and returns zero one or more messages to send to the peer.
443
+func (c *Conversation) Send(msg []byte) ([][]byte, error) {
444
+	switch c.state {
445
+	case statePlaintext:
446
+		return [][]byte{msg}, nil
447
+	case stateEncrypted:
448
+		return c.encode(c.generateData(msg, nil)), nil
449
+	case stateFinished:
450
+		return nil, errors.New("otr: cannot send message because secure conversation has finished")
451
+	}
452
+
453
+	return nil, errors.New("otr: cannot send message in current state")
454
+}
455
+
456
+// SMPQuestion returns the human readable challenge question from the peer.
457
+// It's only valid after Receive has returned SMPSecretNeeded.
458
+func (c *Conversation) SMPQuestion() string {
459
+	return c.smp.question
460
+}
461
+
462
+// Authenticate begins an authentication with the peer. Authentication involves
463
+// an optional challenge message and a shared secret. The authentication
464
+// proceeds until either Receive returns SMPComplete, SMPSecretNeeded (which
465
+// indicates that a new authentication is happening and thus this one was
466
+// aborted) or SMPFailed.
467
+func (c *Conversation) Authenticate(question string, mutualSecret []byte) (toSend [][]byte, err error) {
468
+	if c.state != stateEncrypted {
469
+		err = errors.New("otr: can't authenticate a peer without a secure conversation established")
470
+		return
471
+	}
472
+
473
+	if c.smp.saved != nil {
474
+		c.calcSMPSecret(mutualSecret, false /* they started it */)
475
+
476
+		var out tlv
477
+		var complete bool
478
+		out, complete, err = c.processSMP(*c.smp.saved)
479
+		if complete {
480
+			panic("SMP completed on the first message")
481
+		}
482
+		c.smp.saved = nil
483
+		if out.typ != 0 {
484
+			toSend = c.encode(c.generateData(nil, &out))
485
+		}
486
+		return
487
+	}
488
+
489
+	c.calcSMPSecret(mutualSecret, true /* we started it */)
490
+	outs := c.startSMP(question)
491
+	for _, out := range outs {
492
+		toSend = append(toSend, c.encode(c.generateData(nil, &out))...)
493
+	}
494
+	return
495
+}
496
+
497
+// End ends a secure conversation by generating a termination message for
498
+// the peer and switches to unencrypted communication.
499
+func (c *Conversation) End() (toSend [][]byte) {
500
+	switch c.state {
501
+	case statePlaintext:
502
+		return nil
503
+	case stateEncrypted:
504
+		c.state = statePlaintext
505
+		return c.encode(c.generateData(nil, &tlv{typ: tlvTypeDisconnected}))
506
+	case stateFinished:
507
+		c.state = statePlaintext
508
+		return nil
509
+	}
510
+	panic("unreachable")
511
+}
512
+
513
+// IsEncrypted returns true if a message passed to Send would be encrypted
514
+// before transmission. This result remains valid until the next call to
515
+// Receive or End, which may change the state of the Conversation.
516
+func (c *Conversation) IsEncrypted() bool {
517
+	return c.state == stateEncrypted
518
+}
519
+
520
+var fragmentError = errors.New("otr: invalid OTR fragment")
521
+
522
+// processFragment processes a fragmented OTR message and possibly returns a
523
+// complete message. Fragmented messages look like "?OTR,k,n,msg," where k is
524
+// the fragment number (starting from 1), n is the number of fragments in this
525
+// message and msg is a substring of the base64 encoded message.
526
+func (c *Conversation) processFragment(in []byte) (out []byte, err error) {
527
+	in = in[len(fragmentPrefix):] // remove "?OTR,"
528
+	parts := bytes.Split(in, fragmentPartSeparator)
529
+	if len(parts) != 4 || len(parts[3]) != 0 {
530
+		return nil, fragmentError
531
+	}
532
+
533
+	k, err := strconv.Atoi(string(parts[0]))
534
+	if err != nil {
535
+		return nil, fragmentError
536
+	}
537
+
538
+	n, err := strconv.Atoi(string(parts[1]))
539
+	if err != nil {
540
+		return nil, fragmentError
541
+	}
542
+
543
+	if k < 1 || n < 1 || k > n {
544
+		return nil, fragmentError
545
+	}
546
+
547
+	if k == 1 {
548
+		c.frag = append(c.frag[:0], parts[2]...)
549
+		c.k, c.n = k, n
550
+	} else if n == c.n && k == c.k+1 {
551
+		c.frag = append(c.frag, parts[2]...)
552
+		c.k++
553
+	} else {
554
+		c.frag = c.frag[:0]
555
+		c.n, c.k = 0, 0
556
+	}
557
+
558
+	if c.n > 0 && c.k == c.n {
559
+		c.n, c.k = 0, 0
560
+		return c.frag, nil
561
+	}
562
+
563
+	return nil, nil
564
+}
565
+
566
+func (c *Conversation) generateDHCommit() []byte {
567
+	_, err := io.ReadFull(c.rand(), c.r[:])
568
+	if err != nil {
569
+		panic("otr: short read from random source")
570
+	}
571
+
572
+	var xBytes [dhPrivateBytes]byte
573
+	c.x = c.randMPI(xBytes[:])
574
+	c.gx = new(big.Int).Exp(g, c.x, p)
575
+	c.gy = nil
576
+	c.gxBytes = appendMPI(nil, c.gx)
577
+
578
+	h := sha256.New()
579
+	h.Write(c.gxBytes)
580
+	h.Sum(c.digest[:0])
581
+
582
+	aesCipher, err := aes.NewCipher(c.r[:])
583
+	if err != nil {
584
+		panic(err.Error())
585
+	}
586
+
587
+	var iv [aes.BlockSize]byte
588
+	ctr := cipher.NewCTR(aesCipher, iv[:])
589
+	ctr.XORKeyStream(c.gxBytes, c.gxBytes)
590
+
591
+	return c.serializeDHCommit()
592
+}
593
+
594
+func (c *Conversation) serializeDHCommit() []byte {
595
+	var ret []byte
596
+	ret = appendU16(ret, 2) // protocol version
597
+	ret = append(ret, msgTypeDHCommit)
598
+	ret = appendData(ret, c.gxBytes)
599
+	ret = appendData(ret, c.digest[:])
600
+	return ret
601
+}
602
+
603
+func (c *Conversation) processDHCommit(in []byte) error {
604
+	var ok1, ok2 bool
605
+	c.gxBytes, in, ok1 = getData(in)
606
+	digest, in, ok2 := getData(in)
607
+	if !ok1 || !ok2 || len(in) > 0 {
608
+		return errors.New("otr: corrupt DH commit message")
609
+	}
610
+	copy(c.digest[:], digest)
611
+	return nil
612
+}
613
+
614
+func (c *Conversation) compareToDHCommit(in []byte) (int, error) {
615
+	_, in, ok1 := getData(in)
616
+	digest, in, ok2 := getData(in)
617
+	if !ok1 || !ok2 || len(in) > 0 {
618
+		return 0, errors.New("otr: corrupt DH commit message")
619
+	}
620
+	return bytes.Compare(c.digest[:], digest), nil
621
+}
622
+
623
+func (c *Conversation) generateDHKey() []byte {
624
+	var yBytes [dhPrivateBytes]byte
625
+	c.y = c.randMPI(yBytes[:])
626
+	c.gy = new(big.Int).Exp(g, c.y, p)
627
+	return c.serializeDHKey()
628
+}
629
+
630
+func (c *Conversation) serializeDHKey() []byte {
631
+	var ret []byte
632
+	ret = appendU16(ret, 2) // protocol version
633
+	ret = append(ret, msgTypeDHKey)
634
+	ret = appendMPI(ret, c.gy)
635
+	return ret
636
+}
637
+
638
+func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) {
639
+	gy, in, ok := getMPI(in)
640
+	if !ok {
641
+		err = errors.New("otr: corrupt DH key message")
642
+		return
643
+	}
644
+	if gy.Cmp(g) < 0 || gy.Cmp(pMinus2) > 0 {
645
+		err = errors.New("otr: DH value out of range")
646
+		return
647
+	}
648
+	if c.gy != nil {
649
+		isSame = c.gy.Cmp(gy) == 0
650
+		return
651
+	}
652
+	c.gy = gy
653
+	return
654
+}
655
+
656
+func (c *Conversation) generateEncryptedSignature(keys *akeKeys, xFirst bool) ([]byte, []byte) {
657
+	var xb []byte
658
+	xb = c.PrivateKey.PublicKey.Serialize(xb)
659
+
660
+	var verifyData []byte
661
+	if xFirst {
662
+		verifyData = appendMPI(verifyData, c.gx)
663
+		verifyData = appendMPI(verifyData, c.gy)
664
+	} else {
665
+		verifyData = appendMPI(verifyData, c.gy)
666
+		verifyData = appendMPI(verifyData, c.gx)
667
+	}
668
+	verifyData = append(verifyData, xb...)
669
+	verifyData = appendU32(verifyData, c.myKeyId)
670
+
671
+	mac := hmac.New(sha256.New, keys.m1[:])
672
+	mac.Write(verifyData)
673
+	mb := mac.Sum(nil)
674
+
675
+	xb = appendU32(xb, c.myKeyId)
676
+	xb = append(xb, c.PrivateKey.Sign(c.rand(), mb)...)
677
+
678
+	aesCipher, err := aes.NewCipher(keys.c[:])
679
+	if err != nil {
680
+		panic(err.Error())
681
+	}
682
+	var iv [aes.BlockSize]byte
683
+	ctr := cipher.NewCTR(aesCipher, iv[:])
684
+	ctr.XORKeyStream(xb, xb)
685
+
686
+	mac = hmac.New(sha256.New, keys.m2[:])
687
+	encryptedSig := appendData(nil, xb)
688
+	mac.Write(encryptedSig)
689
+
690
+	return encryptedSig, mac.Sum(nil)
691
+}
692
+
693
+func (c *Conversation) generateRevealSig() []byte {
694
+	s := new(big.Int).Exp(c.gy, c.x, p)
695
+	c.calcAKEKeys(s)
696
+	c.myKeyId++
697
+
698
+	encryptedSig, mac := c.generateEncryptedSignature(&c.revealKeys, true /* gx comes first */)
699
+
700
+	c.myCurrentDHPub = c.gx
701
+	c.myCurrentDHPriv = c.x
702
+	c.rotateDHKeys()
703
+	incCounter(&c.myCounter)
704
+
705
+	var ret []byte
706
+	ret = appendU16(ret, 2)
707
+	ret = append(ret, msgTypeRevealSig)
708
+	ret = appendData(ret, c.r[:])
709
+	ret = append(ret, encryptedSig...)
710
+	ret = append(ret, mac[:20]...)
711
+	return ret
712
+}
713
+
714
+func (c *Conversation) processEncryptedSig(encryptedSig, theirMAC []byte, keys *akeKeys, xFirst bool) error {
715
+	mac := hmac.New(sha256.New, keys.m2[:])
716
+	mac.Write(appendData(nil, encryptedSig))
717
+	myMAC := mac.Sum(nil)[:20]
718
+
719
+	if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
720
+		return errors.New("bad signature MAC in encrypted signature")
721
+	}
722
+
723
+	aesCipher, err := aes.NewCipher(keys.c[:])
724
+	if err != nil {
725
+		panic(err.Error())
726
+	}
727
+	var iv [aes.BlockSize]byte
728
+	ctr := cipher.NewCTR(aesCipher, iv[:])
729
+	ctr.XORKeyStream(encryptedSig, encryptedSig)
730
+
731
+	sig := encryptedSig
732
+	sig, ok1 := c.TheirPublicKey.Parse(sig)
733
+	keyId, sig, ok2 := getU32(sig)
734
+	if !ok1 || !ok2 {
735
+		return errors.New("otr: corrupt encrypted signature")
736
+	}
737
+
738
+	var verifyData []byte
739
+	if xFirst {
740
+		verifyData = appendMPI(verifyData, c.gx)
741
+		verifyData = appendMPI(verifyData, c.gy)
742
+	} else {
743
+		verifyData = appendMPI(verifyData, c.gy)
744
+		verifyData = appendMPI(verifyData, c.gx)
745
+	}
746
+	verifyData = c.TheirPublicKey.Serialize(verifyData)
747
+	verifyData = appendU32(verifyData, keyId)
748
+
749
+	mac = hmac.New(sha256.New, keys.m1[:])
750
+	mac.Write(verifyData)
751
+	mb := mac.Sum(nil)
752
+
753
+	sig, ok1 = c.TheirPublicKey.Verify(mb, sig)
754
+	if !ok1 {
755
+		return errors.New("bad signature in encrypted signature")
756
+	}
757
+	if len(sig) > 0 {
758
+		return errors.New("corrupt encrypted signature")
759
+	}
760
+
761
+	c.theirKeyId = keyId
762
+	zero(c.theirLastCtr[:])
763
+	return nil
764
+}
765
+
766
+func (c *Conversation) processRevealSig(in []byte) error {
767
+	r, in, ok1 := getData(in)
768
+	encryptedSig, in, ok2 := getData(in)
769
+	theirMAC := in
770
+	if !ok1 || !ok2 || len(theirMAC) != 20 {
771
+		return errors.New("otr: corrupt reveal signature message")
772
+	}
773
+
774
+	aesCipher, err := aes.NewCipher(r)
775
+	if err != nil {
776
+		return errors.New("otr: cannot create AES cipher from reveal signature message: " + err.Error())
777
+	}
778
+	var iv [aes.BlockSize]byte
779
+	ctr := cipher.NewCTR(aesCipher, iv[:])
780
+	ctr.XORKeyStream(c.gxBytes, c.gxBytes)
781
+	h := sha256.New()
782
+	h.Write(c.gxBytes)
783
+	digest := h.Sum(nil)
784
+	if len(digest) != len(c.digest) || subtle.ConstantTimeCompare(digest, c.digest[:]) == 0 {
785
+		return errors.New("otr: bad commit MAC in reveal signature message")
786
+	}
787
+	var rest []byte
788
+	c.gx, rest, ok1 = getMPI(c.gxBytes)
789
+	if !ok1 || len(rest) > 0 {
790
+		return errors.New("otr: gx corrupt after decryption")
791
+	}
792
+	if c.gx.Cmp(g) < 0 || c.gx.Cmp(pMinus2) > 0 {
793
+		return errors.New("otr: DH value out of range")
794
+	}
795
+	s := new(big.Int).Exp(c.gx, c.y, p)
796
+	c.calcAKEKeys(s)
797
+
798
+	if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.revealKeys, true /* gx comes first */); err != nil {
799
+		return errors.New("otr: in reveal signature message: " + err.Error())
800
+	}
801
+
802
+	c.theirCurrentDHPub = c.gx
803
+	c.theirLastDHPub = nil
804
+
805
+	return nil
806
+}
807
+
808
+func (c *Conversation) generateSig() []byte {
809
+	c.myKeyId++
810
+
811
+	encryptedSig, mac := c.generateEncryptedSignature(&c.sigKeys, false /* gy comes first */)
812
+
813
+	c.myCurrentDHPub = c.gy
814
+	c.myCurrentDHPriv = c.y
815
+	c.rotateDHKeys()
816
+	incCounter(&c.myCounter)
817
+
818
+	var ret []byte
819
+	ret = appendU16(ret, 2)
820
+	ret = append(ret, msgTypeSig)
821
+	ret = append(ret, encryptedSig...)
822
+	ret = append(ret, mac[:macPrefixBytes]...)
823
+	return ret
824
+}
825
+
826
+func (c *Conversation) processSig(in []byte) error {
827
+	encryptedSig, in, ok1 := getData(in)
828
+	theirMAC := in
829
+	if !ok1 || len(theirMAC) != macPrefixBytes {
830
+		return errors.New("otr: corrupt signature message")
831
+	}
832
+
833
+	if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.sigKeys, false /* gy comes first */); err != nil {
834
+		return errors.New("otr: in signature message: " + err.Error())
835
+	}
836
+
837
+	c.theirCurrentDHPub = c.gy
838
+	c.theirLastDHPub = nil
839
+
840
+	return nil
841
+}
842
+
843
+func (c *Conversation) rotateDHKeys() {
844
+	// evict slots using our retired key id
845
+	for i := range c.keySlots {
846
+		slot := &c.keySlots[i]
847
+		if slot.used && slot.myKeyId == c.myKeyId-1 {
848
+			slot.used = false
849
+			c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
850
+		}
851
+	}
852
+
853
+	c.myLastDHPriv = c.myCurrentDHPriv
854
+	c.myLastDHPub = c.myCurrentDHPub
855
+
856
+	var xBytes [dhPrivateBytes]byte
857
+	c.myCurrentDHPriv = c.randMPI(xBytes[:])
858
+	c.myCurrentDHPub = new(big.Int).Exp(g, c.myCurrentDHPriv, p)
859
+	c.myKeyId++
860
+}
861
+
862
+func (c *Conversation) processData(in []byte) (out []byte, tlvs []tlv, err error) {
863
+	origIn := in
864
+	flags, in, ok1 := getU8(in)
865
+	theirKeyId, in, ok2 := getU32(in)
866
+	myKeyId, in, ok3 := getU32(in)
867
+	y, in, ok4 := getMPI(in)
868
+	counter, in, ok5 := getNBytes(in, 8)
869
+	encrypted, in, ok6 := getData(in)
870
+	macedData := origIn[:len(origIn)-len(in)]
871
+	theirMAC, in, ok7 := getNBytes(in, macPrefixBytes)
872
+	_, in, ok8 := getData(in)
873
+	if !ok1 || !ok2 || !ok3 || !ok4 || !ok5 || !ok6 || !ok7 || !ok8 || len(in) > 0 {
874
+		err = errors.New("otr: corrupt data message")
875
+		return
876
+	}
877
+
878
+	ignoreErrors := flags&1 != 0
879
+
880
+	slot, err := c.calcDataKeys(myKeyId, theirKeyId)
881
+	if err != nil {
882
+		if ignoreErrors {
883
+			err = nil
884
+		}
885
+		return
886
+	}
887
+
888
+	mac := hmac.New(sha1.New, slot.recvMACKey)
889
+	mac.Write([]byte{0, 2, 3})
890
+	mac.Write(macedData)
891
+	myMAC := mac.Sum(nil)
892
+	if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
893
+		if !ignoreErrors {
894
+			err = errors.New("otr: bad MAC on data message")
895
+		}
896
+		return
897
+	}
898
+
899
+	if bytes.Compare(counter, slot.theirLastCtr[:]) <= 0 {
900
+		err = errors.New("otr: counter regressed")
901
+		return
902
+	}
903
+	copy(slot.theirLastCtr[:], counter)
904
+
905
+	var iv [aes.BlockSize]byte
906
+	copy(iv[:], counter)
907
+	aesCipher, err := aes.NewCipher(slot.recvAESKey)
908
+	if err != nil {
909
+		panic(err.Error())
910
+	}
911
+	ctr := cipher.NewCTR(aesCipher, iv[:])
912
+	ctr.XORKeyStream(encrypted, encrypted)
913
+	decrypted := encrypted
914
+
915
+	if myKeyId == c.myKeyId {
916
+		c.rotateDHKeys()
917
+	}
918
+	if theirKeyId == c.theirKeyId {
919
+		// evict slots using their retired key id
920
+		for i := range c.keySlots {
921
+			slot := &c.keySlots[i]
922
+			if slot.used && slot.theirKeyId == theirKeyId-1 {
923
+				slot.used = false
924
+				c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
925
+			}
926
+		}
927
+
928
+		c.theirLastDHPub = c.theirCurrentDHPub
929
+		c.theirKeyId++
930
+		c.theirCurrentDHPub = y
931
+	}
932
+
933
+	if nulPos := bytes.IndexByte(decrypted, 0); nulPos >= 0 {
934
+		out = decrypted[:nulPos]
935
+		tlvData := decrypted[nulPos+1:]
936
+		for len(tlvData) > 0 {
937
+			var t tlv
938
+			var ok1, ok2, ok3 bool
939
+
940
+			t.typ, tlvData, ok1 = getU16(tlvData)
941
+			t.length, tlvData, ok2 = getU16(tlvData)
942
+			t.data, tlvData, ok3 = getNBytes(tlvData, int(t.length))
943
+			if !ok1 || !ok2 || !ok3 {
944
+				err = errors.New("otr: corrupt tlv data")
945
+				return
946
+			}
947
+			tlvs = append(tlvs, t)
948
+		}
949
+	} else {
950
+		out = decrypted
951
+	}
952
+
953
+	return
954
+}
955
+
956
+func (c *Conversation) generateData(msg []byte, extra *tlv) []byte {
957
+	slot, err := c.calcDataKeys(c.myKeyId-1, c.theirKeyId)
958
+	if err != nil {
959
+		panic("otr: failed to generate sending keys: " + err.Error())
960
+	}
961
+
962
+	var plaintext []byte
963
+	plaintext = append(plaintext, msg...)
964
+	plaintext = append(plaintext, 0)
965
+
966
+	padding := paddingGranularity - ((len(plaintext) + 4) % paddingGranularity)
967
+	plaintext = appendU16(plaintext, tlvTypePadding)
968
+	plaintext = appendU16(plaintext, uint16(padding))
969
+	for i := 0; i < padding; i++ {
970
+		plaintext = append(plaintext, 0)
971
+	}
972
+
973
+	if extra != nil {
974
+		plaintext = appendU16(plaintext, extra.typ)
975
+		plaintext = appendU16(plaintext, uint16(len(extra.data)))
976
+		plaintext = append(plaintext, extra.data...)
977
+	}
978
+
979
+	encrypted := make([]byte, len(plaintext))
980
+
981
+	var iv [aes.BlockSize]byte
982
+	copy(iv[:], c.myCounter[:])
983
+	aesCipher, err := aes.NewCipher(slot.sendAESKey)
984
+	if err != nil {
985
+		panic(err.Error())
986
+	}
987
+	ctr := cipher.NewCTR(aesCipher, iv[:])
988
+	ctr.XORKeyStream(encrypted, plaintext)
989
+
990
+	var ret []byte
991
+	ret = appendU16(ret, 2)
992
+	ret = append(ret, msgTypeData)
993
+	ret = append(ret, 0 /* flags */)
994
+	ret = appendU32(ret, c.myKeyId-1)
995
+	ret = appendU32(ret, c.theirKeyId)
996
+	ret = appendMPI(ret, c.myCurrentDHPub)
997
+	ret = append(ret, c.myCounter[:]...)
998
+	ret = appendData(ret, encrypted)
999
+
1000
+	mac := hmac.New(sha1.New, slot.sendMACKey)
1001
+	mac.Write(ret)
1002
+	ret = append(ret, mac.Sum(nil)[:macPrefixBytes]...)
1003
+	ret = appendData(ret, c.oldMACs)
1004
+	c.oldMACs = nil
1005
+	incCounter(&c.myCounter)
1006
+
1007
+	return ret
1008
+}
1009
+
1010
+func incCounter(counter *[8]byte) {
1011
+	for i := 7; i >= 0; i-- {
1012
+		counter[i]++
1013
+		if counter[i] > 0 {
1014
+			break
1015
+		}
1016
+	}
1017
+}
1018
+
1019
+// calcDataKeys computes the keys used to encrypt a data message given the key
1020
+// IDs.
1021
+func (c *Conversation) calcDataKeys(myKeyId, theirKeyId uint32) (slot *keySlot, err error) {
1022
+	// Check for a cache hit.
1023
+	for i := range c.keySlots {
1024
+		slot = &c.keySlots[i]
1025
+		if slot.used && slot.theirKeyId == theirKeyId && slot.myKeyId == myKeyId {
1026
+			return
1027
+		}
1028
+	}
1029
+
1030
+	// Find an empty slot to write into.
1031
+	slot = nil
1032
+	for i := range c.keySlots {
1033
+		if !c.keySlots[i].used {
1034
+			slot = &c.keySlots[i]
1035
+			break
1036
+		}
1037
+	}
1038
+	if slot == nil {
1039
+		return nil, errors.New("otr: internal error: no more key slots")
1040
+	}
1041
+
1042
+	var myPriv, myPub, theirPub *big.Int
1043
+
1044
+	if myKeyId == c.myKeyId {
1045
+		myPriv = c.myCurrentDHPriv
1046
+		myPub = c.myCurrentDHPub
1047
+	} else if myKeyId == c.myKeyId-1 {
1048
+		myPriv = c.myLastDHPriv
1049
+		myPub = c.myLastDHPub
1050
+	} else {
1051
+		err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when I'm on " + strconv.FormatUint(uint64(c.myKeyId), 10))
1052
+		return
1053
+	}
1054
+
1055
+	if theirKeyId == c.theirKeyId {
1056
+		theirPub = c.theirCurrentDHPub
1057
+	} else if theirKeyId == c.theirKeyId-1 && c.theirLastDHPub != nil {
1058
+		theirPub = c.theirLastDHPub
1059
+	} else {
1060
+		err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when they're on " + strconv.FormatUint(uint64(c.myKeyId), 10))
1061
+		return
1062
+	}
1063
+
1064
+	var sendPrefixByte, recvPrefixByte [1]byte
1065
+
1066
+	if myPub.Cmp(theirPub) > 0 {
1067
+		// we're the high end
1068
+		sendPrefixByte[0], recvPrefixByte[0] = 1, 2
1069
+	} else {
1070
+		// we're the low end
1071
+		sendPrefixByte[0], recvPrefixByte[0] = 2, 1
1072
+	}
1073
+
1074
+	s := new(big.Int).Exp(theirPub, myPriv, p)
1075
+	sBytes := appendMPI(nil, s)
1076
+
1077
+	h := sha1.New()
1078
+	h.Write(sendPrefixByte[:])
1079
+	h.Write(sBytes)
1080
+	slot.sendAESKey = h.Sum(slot.sendAESKey[:0])[:16]
1081
+
1082
+	h.Reset()
1083
+	h.Write(slot.sendAESKey)
1084
+	slot.sendMACKey = h.Sum(slot.sendMACKey[:0])
1085
+
1086
+	h.Reset()
1087
+	h.Write(recvPrefixByte[:])
1088
+	h.Write(sBytes)
1089
+	slot.recvAESKey = h.Sum(slot.recvAESKey[:0])[:16]
1090
+
1091
+	h.Reset()
1092
+	h.Write(slot.recvAESKey)
1093
+	slot.recvMACKey = h.Sum(slot.recvMACKey[:0])
1094
+
1095
+	slot.theirKeyId = theirKeyId
1096
+	slot.myKeyId = myKeyId
1097
+	slot.used = true
1098
+
1099
+	zero(slot.theirLastCtr[:])
1100
+	return
1101
+}
1102
+
1103
+func (c *Conversation) calcAKEKeys(s *big.Int) {
1104
+	mpi := appendMPI(nil, s)
1105
+	h := sha256.New()
1106
+
1107
+	var cBytes [32]byte
1108
+	hashWithPrefix(c.SSID[:], 0, mpi, h)
1109
+
1110
+	hashWithPrefix(cBytes[:], 1, mpi, h)
1111
+	copy(c.revealKeys.c[:], cBytes[:16])
1112
+	copy(c.sigKeys.c[:], cBytes[16:])
1113
+
1114
+	hashWithPrefix(c.revealKeys.m1[:], 2, mpi, h)
1115
+	hashWithPrefix(c.revealKeys.m2[:], 3, mpi, h)
1116
+	hashWithPrefix(c.sigKeys.m1[:], 4, mpi, h)
1117
+	hashWithPrefix(c.sigKeys.m2[:], 5, mpi, h)
1118
+}
1119
+
1120
+func hashWithPrefix(out []byte, prefix byte, in []byte, h hash.Hash) {
1121
+	h.Reset()
1122
+	var p [1]byte
1123
+	p[0] = prefix
1124
+	h.Write(p[:])
1125
+	h.Write(in)
1126
+	if len(out) == h.Size() {
1127
+		h.Sum(out[:0])
1128
+	} else {
1129
+		digest := h.Sum(nil)
1130
+		copy(out, digest)
1131
+	}
1132
+}
1133
+
1134
+func (c *Conversation) encode(msg []byte) [][]byte {
1135
+	b64 := make([]byte, base64.StdEncoding.EncodedLen(len(msg))+len(msgPrefix)+1)
1136
+	base64.StdEncoding.Encode(b64[len(msgPrefix):], msg)
1137
+	copy(b64, msgPrefix)
1138
+	b64[len(b64)-1] = '.'
1139
+
1140
+	if c.FragmentSize < minFragmentSize || len(b64) <= c.FragmentSize {
1141
+		// We can encode this in a single fragment.
1142
+		return [][]byte{b64}
1143
+	}
1144
+
1145
+	// We have to fragment this message.
1146
+	var ret [][]byte
1147
+	bytesPerFragment := c.FragmentSize - minFragmentSize
1148
+	numFragments := (len(b64) + bytesPerFragment) / bytesPerFragment
1149
+
1150
+	for i := 0; i < numFragments; i++ {
1151
+		frag := []byte("?OTR," + strconv.Itoa(i+1) + "," + strconv.Itoa(numFragments) + ",")
1152
+		todo := bytesPerFragment
1153
+		if todo > len(b64) {
1154
+			todo = len(b64)
1155
+		}
1156
+		frag = append(frag, b64[:todo]...)
1157
+		b64 = b64[todo:]
1158
+		frag = append(frag, ',')
1159
+		ret = append(ret, frag)
1160
+	}
1161
+
1162
+	return ret
1163
+}
1164
+
1165
+func (c *Conversation) reset() {
1166
+	c.myKeyId = 0
1167
+
1168
+	for i := range c.keySlots {
1169
+		c.keySlots[i].used = false
1170
+	}
1171
+}
1172
+
1173
+type PublicKey struct {
1174
+	dsa.PublicKey
1175
+}
1176
+
1177
+func (pk *PublicKey) Parse(in []byte) ([]byte, bool) {
1178
+	var ok bool
1179
+	var pubKeyType uint16
1180
+
1181
+	if pubKeyType, in, ok = getU16(in); !ok || pubKeyType != 0 {
1182
+		return nil, false
1183
+	}
1184
+	if pk.P, in, ok = getMPI(in); !ok {
1185
+		return nil, false
1186
+	}
1187
+	if pk.Q, in, ok = getMPI(in); !ok {
1188
+		return nil, false
1189
+	}
1190
+	if pk.G, in, ok = getMPI(in); !ok {
1191
+		return nil, false
1192
+	}
1193
+	if pk.Y, in, ok = getMPI(in); !ok {
1194
+		return nil, false
1195
+	}
1196
+
1197
+	return in, true
1198
+}
1199
+
1200
+func (pk *PublicKey) Serialize(in []byte) []byte {
1201
+	in = appendU16(in, 0)
1202
+	in = appendMPI(in, pk.P)
1203
+	in = appendMPI(in, pk.Q)
1204
+	in = appendMPI(in, pk.G)
1205
+	in = appendMPI(in, pk.Y)
1206
+	return in
1207
+}
1208
+
1209
+// Fingerprint returns the 20-byte, binary fingerprint of the PublicKey.
1210
+func (pk *PublicKey) Fingerprint() []byte {
1211
+	b := pk.Serialize(nil)
1212
+	h := sha1.New()
1213
+	h.Write(b[2:])
1214
+	return h.Sum(nil)
1215
+}
1216
+
1217
+func (pk *PublicKey) Verify(hashed, sig []byte) ([]byte, bool) {
1218
+	if len(sig) != 2*dsaSubgroupBytes {
1219
+		return nil, false
1220
+	}
1221
+	r := new(big.Int).SetBytes(sig[:dsaSubgroupBytes])
1222
+	s := new(big.Int).SetBytes(sig[dsaSubgroupBytes:])
1223
+	ok := dsa.Verify(&pk.PublicKey, hashed, r, s)
1224
+	return sig[dsaSubgroupBytes*2:], ok
1225
+}
1226
+
1227
+type PrivateKey struct {
1228
+	PublicKey
1229
+	dsa.PrivateKey
1230
+}
1231
+
1232
+func (priv *PrivateKey) Sign(rand io.Reader, hashed []byte) []byte {
1233
+	r, s, err := dsa.Sign(rand, &priv.PrivateKey, hashed)
1234
+	if err != nil {
1235
+		panic(err.Error())
1236
+	}
1237
+	rBytes := r.Bytes()
1238
+	sBytes := s.Bytes()
1239
+	if len(rBytes) > dsaSubgroupBytes || len(sBytes) > dsaSubgroupBytes {
1240
+		panic("DSA signature too large")
1241
+	}
1242
+
1243
+	out := make([]byte, 2*dsaSubgroupBytes)
1244
+	copy(out[dsaSubgroupBytes-len(rBytes):], rBytes)
1245
+	copy(out[len(out)-len(sBytes):], sBytes)
1246
+	return out
1247
+}
1248
+
1249
+func (priv *PrivateKey) Serialize(in []byte) []byte {
1250
+	in = priv.PublicKey.Serialize(in)
1251
+	in = appendMPI(in, priv.PrivateKey.X)
1252
+	return in
1253
+}
1254
+
1255
+func (priv *PrivateKey) Parse(in []byte) ([]byte, bool) {
1256
+	in, ok := priv.PublicKey.Parse(in)
1257
+	if !ok {
1258
+		return in, ok
1259
+	}
1260
+	priv.PrivateKey.PublicKey = priv.PublicKey.PublicKey
1261
+	priv.PrivateKey.X, in, ok = getMPI(in)
1262
+	return in, ok
1263
+}
1264
+
1265
+func (priv *PrivateKey) Generate(rand io.Reader) {
1266
+	if err := dsa.GenerateParameters(&priv.PrivateKey.PublicKey.Parameters, rand, dsa.L1024N160); err != nil {
1267
+		panic(err.Error())
1268
+	}
1269
+	if err := dsa.GenerateKey(&priv.PrivateKey, rand); err != nil {
1270
+		panic(err.Error())
1271
+	}
1272
+	priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey
1273
+}
1274
+
1275
+func notHex(r rune) bool {
1276
+	if r >= '0' && r <= '9' ||
1277
+		r >= 'a' && r <= 'f' ||
1278
+		r >= 'A' && r <= 'F' {
1279
+		return false
1280
+	}
1281
+
1282
+	return true
1283
+}
1284
+
1285
+// Import parses the contents of a libotr private key file.
1286
+func (priv *PrivateKey) Import(in []byte) bool {
1287
+	mpiStart := []byte(" #")
1288
+
1289
+	mpis := make([]*big.Int, 5)
1290
+
1291
+	for i := 0; i < len(mpis); i++ {
1292
+		start := bytes.Index(in, mpiStart)
1293
+		if start == -1 {
1294
+			return false
1295
+		}
1296
+		in = in[start+len(mpiStart):]
1297
+		end := bytes.IndexFunc(in, notHex)
1298
+		if end == -1 {
1299
+			return false
1300
+		}
1301
+		hexBytes := in[:end]
1302
+		in = in[end:]
1303
+
1304
+		if len(hexBytes)&1 != 0 {
1305
+			return false
1306
+		}
1307
+
1308
+		mpiBytes := make([]byte, len(hexBytes)/2)
1309
+		if _, err := hex.Decode(mpiBytes, hexBytes); err != nil {
1310
+			return false
1311
+		}
1312
+
1313
+		mpis[i] = new(big.Int).SetBytes(mpiBytes)
1314
+	}
1315
+
1316
+	for _, mpi := range mpis {
1317
+		if mpi.Sign() <= 0 {
1318
+			return false
1319
+		}
1320
+	}
1321
+
1322
+	priv.PrivateKey.P = mpis[0]
1323
+	priv.PrivateKey.Q = mpis[1]
1324
+	priv.PrivateKey.G = mpis[2]
1325
+	priv.PrivateKey.Y = mpis[3]
1326
+	priv.PrivateKey.X = mpis[4]
1327
+	priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey
1328
+
1329
+	a := new(big.Int).Exp(priv.PrivateKey.G, priv.PrivateKey.X, priv.PrivateKey.P)
1330
+	return a.Cmp(priv.PrivateKey.Y) == 0
1331
+}
1332
+
1333
+func getU8(in []byte) (uint8, []byte, bool) {
1334
+	if len(in) < 1 {
1335
+		return 0, in, false
1336
+	}
1337
+	return in[0], in[1:], true
1338
+}
1339
+
1340
+func getU16(in []byte) (uint16, []byte, bool) {
1341
+	if len(in) < 2 {
1342
+		return 0, in, false
1343
+	}
1344
+	r := uint16(in[0])<<8 | uint16(in[1])
1345
+	return r, in[2:], true
1346
+}
1347
+
1348
+func getU32(in []byte) (uint32, []byte, bool) {
1349
+	if len(in) < 4 {
1350
+		return 0, in, false
1351
+	}
1352
+	r := uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3])
1353
+	return r, in[4:], true
1354
+}
1355
+
1356
+func getMPI(in []byte) (*big.Int, []byte, bool) {
1357
+	l, in, ok := getU32(in)
1358
+	if !ok || uint32(len(in)) < l {
1359
+		return nil, in, false
1360
+	}
1361
+	r := new(big.Int).SetBytes(in[:l])
1362
+	return r, in[l:], true
1363
+}
1364
+
1365
+func getData(in []byte) ([]byte, []byte, bool) {
1366
+	l, in, ok := getU32(in)
1367
+	if !ok || uint32(len(in)) < l {
1368
+		return nil, in, false
1369
+	}
1370
+	return in[:l], in[l:], true
1371
+}
1372
+
1373
+func getNBytes(in []byte, n int) ([]byte, []byte, bool) {
1374
+	if len(in) < n {
1375
+		return nil, in, false
1376
+	}
1377
+	return in[:n], in[n:], true
1378
+}
1379
+
1380
+func appendU16(out []byte, v uint16) []byte {
1381
+	out = append(out, byte(v>>8), byte(v))
1382
+	return out
1383
+}
1384
+
1385
+func appendU32(out []byte, v uint32) []byte {
1386
+	out = append(out, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
1387
+	return out
1388
+}
1389
+
1390
+func appendData(out, v []byte) []byte {
1391
+	out = appendU32(out, uint32(len(v)))
1392
+	out = append(out, v...)
1393
+	return out
1394
+}
1395
+
1396
+func appendMPI(out []byte, v *big.Int) []byte {
1397
+	vBytes := v.Bytes()
1398
+	out = appendU32(out, uint32(len(vBytes)))
1399
+	out = append(out, vBytes...)
1400
+	return out
1401
+}
1402
+
1403
+func appendMPIs(out []byte, mpis ...*big.Int) []byte {
1404
+	for _, mpi := range mpis {
1405
+		out = appendMPI(out, mpi)
1406
+	}
1407
+	return out
1408
+}
1409
+
1410
+func zero(b []byte) {
1411
+	for i := range b {
1412
+		b[i] = 0
1413
+	}
1414
+}
0 1415
new file mode 100644
... ...
@@ -0,0 +1,572 @@
0
+// Copyright 2012 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// This file implements the Socialist Millionaires Protocol as described in
5
+// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html. The protocol
6
+// specification is required in order to understand this code and, where
7
+// possible, the variable names in the code match up with the spec.
8
+
9
+package otr
10
+
11
+import (
12
+	"bytes"
13
+	"crypto/sha256"
14
+	"errors"
15
+	"hash"
16
+	"math/big"
17
+)
18
+
19
+type smpFailure string
20
+
21
+func (s smpFailure) Error() string {
22
+	return string(s)
23
+}
24
+
25
+var smpFailureError = smpFailure("otr: SMP protocol failed")
26
+var smpSecretMissingError = smpFailure("otr: mutual secret needed")
27
+
28
+const smpVersion = 1
29
+
30
+const (
31
+	smpState1 = iota
32
+	smpState2
33
+	smpState3
34
+	smpState4
35
+)
36
+
37
+type smpState struct {
38
+	state                  int
39
+	a2, a3, b2, b3, pb, qb *big.Int
40
+	g2a, g3a               *big.Int
41
+	g2, g3                 *big.Int
42
+	g3b, papb, qaqb, ra    *big.Int
43
+	saved                  *tlv
44
+	secret                 *big.Int
45
+	question               string
46
+}
47
+
48
+func (c *Conversation) startSMP(question string) (tlvs []tlv) {
49
+	if c.smp.state != smpState1 {
50
+		tlvs = append(tlvs, c.generateSMPAbort())
51
+	}
52
+	tlvs = append(tlvs, c.generateSMP1(question))
53
+	c.smp.question = ""
54
+	c.smp.state = smpState2
55
+	return
56
+}
57
+
58
+func (c *Conversation) resetSMP() {
59
+	c.smp.state = smpState1
60
+	c.smp.secret = nil
61
+	c.smp.question = ""
62
+}
63
+
64
+func (c *Conversation) processSMP(in tlv) (out tlv, complete bool, err error) {
65
+	data := in.data
66
+
67
+	switch in.typ {
68
+	case tlvTypeSMPAbort:
69
+		if c.smp.state != smpState1 {
70
+			err = smpFailureError
71
+		}
72
+		c.resetSMP()
73
+		return
74
+	case tlvTypeSMP1WithQuestion:
75
+		// We preprocess this into a SMP1 message.
76
+		nulPos := bytes.IndexByte(data, 0)
77
+		if nulPos == -1 {
78
+			err = errors.New("otr: SMP message with question didn't contain a NUL byte")
79
+			return
80
+		}
81
+		c.smp.question = string(data[:nulPos])
82
+		data = data[nulPos+1:]
83
+	}
84
+
85
+	numMPIs, data, ok := getU32(data)
86
+	if !ok || numMPIs > 20 {
87
+		err = errors.New("otr: corrupt SMP message")
88
+		return
89
+	}
90
+
91
+	mpis := make([]*big.Int, numMPIs)
92
+	for i := range mpis {
93
+		var ok bool
94
+		mpis[i], data, ok = getMPI(data)
95
+		if !ok {
96
+			err = errors.New("otr: corrupt SMP message")
97
+			return
98
+		}
99
+	}
100
+
101
+	switch in.typ {
102
+	case tlvTypeSMP1, tlvTypeSMP1WithQuestion:
103
+		if c.smp.state != smpState1 {
104
+			c.resetSMP()
105
+			out = c.generateSMPAbort()
106
+			return
107
+		}
108
+		if c.smp.secret == nil {
109
+			err = smpSecretMissingError
110
+			return
111
+		}
112
+		if err = c.processSMP1(mpis); err != nil {
113
+			return
114
+		}
115
+		c.smp.state = smpState3
116
+		out = c.generateSMP2()
117
+	case tlvTypeSMP2:
118
+		if c.smp.state != smpState2 {
119
+			c.resetSMP()
120
+			out = c.generateSMPAbort()
121
+			return
122
+		}
123
+		if out, err = c.processSMP2(mpis); err != nil {
124
+			out = c.generateSMPAbort()
125
+			return
126
+		}
127
+		c.smp.state = smpState4
128
+	case tlvTypeSMP3:
129
+		if c.smp.state != smpState3 {
130
+			c.resetSMP()
131
+			out = c.generateSMPAbort()
132
+			return
133
+		}
134
+		if out, err = c.processSMP3(mpis); err != nil {
135
+			return
136
+		}
137
+		c.smp.state = smpState1
138
+		c.smp.secret = nil
139
+		complete = true
140
+	case tlvTypeSMP4:
141
+		if c.smp.state != smpState4 {
142
+			c.resetSMP()
143
+			out = c.generateSMPAbort()
144
+			return
145
+		}
146
+		if err = c.processSMP4(mpis); err != nil {
147
+			out = c.generateSMPAbort()
148
+			return
149
+		}
150
+		c.smp.state = smpState1
151
+		c.smp.secret = nil
152
+		complete = true
153
+	default:
154
+		panic("unknown SMP message")
155
+	}
156
+
157
+	return
158
+}
159
+
160
+func (c *Conversation) calcSMPSecret(mutualSecret []byte, weStarted bool) {
161
+	h := sha256.New()
162
+	h.Write([]byte{smpVersion})
163
+	if weStarted {
164
+		h.Write(c.PrivateKey.PublicKey.Fingerprint())
165
+		h.Write(c.TheirPublicKey.Fingerprint())
166
+	} else {
167
+		h.Write(c.TheirPublicKey.Fingerprint())
168
+		h.Write(c.PrivateKey.PublicKey.Fingerprint())
169
+	}
170
+	h.Write(c.SSID[:])
171
+	h.Write(mutualSecret)
172
+	c.smp.secret = new(big.Int).SetBytes(h.Sum(nil))
173
+}
174
+
175
+func (c *Conversation) generateSMP1(question string) tlv {
176
+	var randBuf [16]byte
177
+	c.smp.a2 = c.randMPI(randBuf[:])
178
+	c.smp.a3 = c.randMPI(randBuf[:])
179
+	g2a := new(big.Int).Exp(g, c.smp.a2, p)
180
+	g3a := new(big.Int).Exp(g, c.smp.a3, p)
181
+	h := sha256.New()
182
+
183
+	r2 := c.randMPI(randBuf[:])
184
+	r := new(big.Int).Exp(g, r2, p)
185
+	c2 := new(big.Int).SetBytes(hashMPIs(h, 1, r))
186
+	d2 := new(big.Int).Mul(c.smp.a2, c2)
187
+	d2.Sub(r2, d2)
188
+	d2.Mod(d2, q)
189
+	if d2.Sign() < 0 {
190
+		d2.Add(d2, q)
191
+	}
192
+
193
+	r3 := c.randMPI(randBuf[:])
194
+	r.Exp(g, r3, p)
195
+	c3 := new(big.Int).SetBytes(hashMPIs(h, 2, r))
196
+	d3 := new(big.Int).Mul(c.smp.a3, c3)
197
+	d3.Sub(r3, d3)
198
+	d3.Mod(d3, q)
199
+	if d3.Sign() < 0 {
200
+		d3.Add(d3, q)
201
+	}
202
+
203
+	var ret tlv
204
+	if len(question) > 0 {
205
+		ret.typ = tlvTypeSMP1WithQuestion
206
+		ret.data = append(ret.data, question...)
207
+		ret.data = append(ret.data, 0)
208
+	} else {
209
+		ret.typ = tlvTypeSMP1
210
+	}
211
+	ret.data = appendU32(ret.data, 6)
212
+	ret.data = appendMPIs(ret.data, g2a, c2, d2, g3a, c3, d3)
213
+	return ret
214
+}
215
+
216
+func (c *Conversation) processSMP1(mpis []*big.Int) error {
217
+	if len(mpis) != 6 {
218
+		return errors.New("otr: incorrect number of arguments in SMP1 message")
219
+	}
220
+	g2a := mpis[0]
221
+	c2 := mpis[1]
222
+	d2 := mpis[2]
223
+	g3a := mpis[3]
224
+	c3 := mpis[4]
225
+	d3 := mpis[5]
226
+	h := sha256.New()
227
+
228
+	r := new(big.Int).Exp(g, d2, p)
229
+	s := new(big.Int).Exp(g2a, c2, p)
230
+	r.Mul(r, s)
231
+	r.Mod(r, p)
232
+	t := new(big.Int).SetBytes(hashMPIs(h, 1, r))
233
+	if c2.Cmp(t) != 0 {
234
+		return errors.New("otr: ZKP c2 incorrect in SMP1 message")
235
+	}
236
+	r.Exp(g, d3, p)
237
+	s.Exp(g3a, c3, p)
238
+	r.Mul(r, s)
239
+	r.Mod(r, p)
240
+	t.SetBytes(hashMPIs(h, 2, r))
241
+	if c3.Cmp(t) != 0 {
242
+		return errors.New("otr: ZKP c3 incorrect in SMP1 message")
243
+	}
244
+
245
+	c.smp.g2a = g2a
246
+	c.smp.g3a = g3a
247
+	return nil
248
+}
249
+
250
+func (c *Conversation) generateSMP2() tlv {
251
+	var randBuf [16]byte
252
+	b2 := c.randMPI(randBuf[:])
253
+	c.smp.b3 = c.randMPI(randBuf[:])
254
+	r2 := c.randMPI(randBuf[:])
255
+	r3 := c.randMPI(randBuf[:])
256
+	r4 := c.randMPI(randBuf[:])
257
+	r5 := c.randMPI(randBuf[:])
258
+	r6 := c.randMPI(randBuf[:])
259
+
260
+	g2b := new(big.Int).Exp(g, b2, p)
261
+	g3b := new(big.Int).Exp(g, c.smp.b3, p)
262
+
263
+	r := new(big.Int).Exp(g, r2, p)
264
+	h := sha256.New()
265
+	c2 := new(big.Int).SetBytes(hashMPIs(h, 3, r))
266
+	d2 := new(big.Int).Mul(b2, c2)
267
+	d2.Sub(r2, d2)
268
+	d2.Mod(d2, q)
269
+	if d2.Sign() < 0 {
270
+		d2.Add(d2, q)
271
+	}
272
+
273
+	r.Exp(g, r3, p)
274
+	c3 := new(big.Int).SetBytes(hashMPIs(h, 4, r))
275
+	d3 := new(big.Int).Mul(c.smp.b3, c3)
276
+	d3.Sub(r3, d3)
277
+	d3.Mod(d3, q)
278
+	if d3.Sign() < 0 {
279
+		d3.Add(d3, q)
280
+	}
281
+
282
+	c.smp.g2 = new(big.Int).Exp(c.smp.g2a, b2, p)
283
+	c.smp.g3 = new(big.Int).Exp(c.smp.g3a, c.smp.b3, p)
284
+	c.smp.pb = new(big.Int).Exp(c.smp.g3, r4, p)
285
+	c.smp.qb = new(big.Int).Exp(g, r4, p)
286
+	r.Exp(c.smp.g2, c.smp.secret, p)
287
+	c.smp.qb.Mul(c.smp.qb, r)
288
+	c.smp.qb.Mod(c.smp.qb, p)
289
+
290
+	s := new(big.Int)
291
+	s.Exp(c.smp.g2, r6, p)
292
+	r.Exp(g, r5, p)
293
+	s.Mul(r, s)
294
+	s.Mod(s, p)
295
+	r.Exp(c.smp.g3, r5, p)
296
+	cp := new(big.Int).SetBytes(hashMPIs(h, 5, r, s))
297
+
298
+	// D5 = r5 - r4 cP mod q and D6 = r6 - y cP mod q
299
+
300
+	s.Mul(r4, cp)
301
+	r.Sub(r5, s)
302
+	d5 := new(big.Int).Mod(r, q)
303
+	if d5.Sign() < 0 {
304
+		d5.Add(d5, q)
305
+	}
306
+
307
+	s.Mul(c.smp.secret, cp)
308
+	r.Sub(r6, s)
309
+	d6 := new(big.Int).Mod(r, q)
310
+	if d6.Sign() < 0 {
311
+		d6.Add(d6, q)
312
+	}
313
+
314
+	var ret tlv
315
+	ret.typ = tlvTypeSMP2
316
+	ret.data = appendU32(ret.data, 11)
317
+	ret.data = appendMPIs(ret.data, g2b, c2, d2, g3b, c3, d3, c.smp.pb, c.smp.qb, cp, d5, d6)
318
+	return ret
319
+}
320
+
321
+func (c *Conversation) processSMP2(mpis []*big.Int) (out tlv, err error) {
322
+	if len(mpis) != 11 {
323
+		err = errors.New("otr: incorrect number of arguments in SMP2 message")
324
+		return
325
+	}
326
+	g2b := mpis[0]
327
+	c2 := mpis[1]
328
+	d2 := mpis[2]
329
+	g3b := mpis[3]
330
+	c3 := mpis[4]
331
+	d3 := mpis[5]
332
+	pb := mpis[6]
333
+	qb := mpis[7]
334
+	cp := mpis[8]
335
+	d5 := mpis[9]
336
+	d6 := mpis[10]
337
+	h := sha256.New()
338
+
339
+	r := new(big.Int).Exp(g, d2, p)
340
+	s := new(big.Int).Exp(g2b, c2, p)
341
+	r.Mul(r, s)
342
+	r.Mod(r, p)
343
+	s.SetBytes(hashMPIs(h, 3, r))
344
+	if c2.Cmp(s) != 0 {
345
+		err = errors.New("otr: ZKP c2 failed in SMP2 message")
346
+		return
347
+	}
348
+
349
+	r.Exp(g, d3, p)
350
+	s.Exp(g3b, c3, p)
351
+	r.Mul(r, s)
352
+	r.Mod(r, p)
353
+	s.SetBytes(hashMPIs(h, 4, r))
354
+	if c3.Cmp(s) != 0 {
355
+		err = errors.New("otr: ZKP c3 failed in SMP2 message")
356
+		return
357
+	}
358
+
359
+	c.smp.g2 = new(big.Int).Exp(g2b, c.smp.a2, p)
360
+	c.smp.g3 = new(big.Int).Exp(g3b, c.smp.a3, p)
361
+
362
+	r.Exp(g, d5, p)
363
+	s.Exp(c.smp.g2, d6, p)
364
+	r.Mul(r, s)
365
+	s.Exp(qb, cp, p)
366
+	r.Mul(r, s)
367
+	r.Mod(r, p)
368
+
369
+	s.Exp(c.smp.g3, d5, p)
370
+	t := new(big.Int).Exp(pb, cp, p)
371
+	s.Mul(s, t)
372
+	s.Mod(s, p)
373
+	t.SetBytes(hashMPIs(h, 5, s, r))
374
+	if cp.Cmp(t) != 0 {
375
+		err = errors.New("otr: ZKP cP failed in SMP2 message")
376
+		return
377
+	}
378
+
379
+	var randBuf [16]byte
380
+	r4 := c.randMPI(randBuf[:])
381
+	r5 := c.randMPI(randBuf[:])
382
+	r6 := c.randMPI(randBuf[:])
383
+	r7 := c.randMPI(randBuf[:])
384
+
385
+	pa := new(big.Int).Exp(c.smp.g3, r4, p)
386
+	r.Exp(c.smp.g2, c.smp.secret, p)
387
+	qa := new(big.Int).Exp(g, r4, p)
388
+	qa.Mul(qa, r)
389
+	qa.Mod(qa, p)
390
+
391
+	r.Exp(g, r5, p)
392
+	s.Exp(c.smp.g2, r6, p)
393
+	r.Mul(r, s)
394
+	r.Mod(r, p)
395
+
396
+	s.Exp(c.smp.g3, r5, p)
397
+	cp.SetBytes(hashMPIs(h, 6, s, r))
398
+
399
+	r.Mul(r4, cp)
400
+	d5 = new(big.Int).Sub(r5, r)
401
+	d5.Mod(d5, q)
402
+	if d5.Sign() < 0 {
403
+		d5.Add(d5, q)
404
+	}
405
+
406
+	r.Mul(c.smp.secret, cp)
407
+	d6 = new(big.Int).Sub(r6, r)
408
+	d6.Mod(d6, q)
409
+	if d6.Sign() < 0 {
410
+		d6.Add(d6, q)
411
+	}
412
+
413
+	r.ModInverse(qb, p)
414
+	qaqb := new(big.Int).Mul(qa, r)
415
+	qaqb.Mod(qaqb, p)
416
+
417
+	ra := new(big.Int).Exp(qaqb, c.smp.a3, p)
418
+	r.Exp(qaqb, r7, p)
419
+	s.Exp(g, r7, p)
420
+	cr := new(big.Int).SetBytes(hashMPIs(h, 7, s, r))
421
+
422
+	r.Mul(c.smp.a3, cr)
423
+	d7 := new(big.Int).Sub(r7, r)
424
+	d7.Mod(d7, q)
425
+	if d7.Sign() < 0 {
426
+		d7.Add(d7, q)
427
+	}
428
+
429
+	c.smp.g3b = g3b
430
+	c.smp.qaqb = qaqb
431
+
432
+	r.ModInverse(pb, p)
433
+	c.smp.papb = new(big.Int).Mul(pa, r)
434
+	c.smp.papb.Mod(c.smp.papb, p)
435
+	c.smp.ra = ra
436
+
437
+	out.typ = tlvTypeSMP3
438
+	out.data = appendU32(out.data, 8)
439
+	out.data = appendMPIs(out.data, pa, qa, cp, d5, d6, ra, cr, d7)
440
+	return
441
+}
442
+
443
+func (c *Conversation) processSMP3(mpis []*big.Int) (out tlv, err error) {
444
+	if len(mpis) != 8 {
445
+		err = errors.New("otr: incorrect number of arguments in SMP3 message")
446
+		return
447
+	}
448
+	pa := mpis[0]
449
+	qa := mpis[1]
450
+	cp := mpis[2]
451
+	d5 := mpis[3]
452
+	d6 := mpis[4]
453
+	ra := mpis[5]
454
+	cr := mpis[6]
455
+	d7 := mpis[7]
456
+	h := sha256.New()
457
+
458
+	r := new(big.Int).Exp(g, d5, p)
459
+	s := new(big.Int).Exp(c.smp.g2, d6, p)
460
+	r.Mul(r, s)
461
+	s.Exp(qa, cp, p)
462
+	r.Mul(r, s)
463
+	r.Mod(r, p)
464
+
465
+	s.Exp(c.smp.g3, d5, p)
466
+	t := new(big.Int).Exp(pa, cp, p)
467
+	s.Mul(s, t)
468
+	s.Mod(s, p)
469
+	t.SetBytes(hashMPIs(h, 6, s, r))
470
+	if t.Cmp(cp) != 0 {
471
+		err = errors.New("otr: ZKP cP failed in SMP3 message")
472
+		return
473
+	}
474
+
475
+	r.ModInverse(c.smp.qb, p)
476
+	qaqb := new(big.Int).Mul(qa, r)
477
+	qaqb.Mod(qaqb, p)
478
+
479
+	r.Exp(qaqb, d7, p)
480
+	s.Exp(ra, cr, p)
481
+	r.Mul(r, s)
482
+	r.Mod(r, p)
483
+
484
+	s.Exp(g, d7, p)
485
+	t.Exp(c.smp.g3a, cr, p)
486
+	s.Mul(s, t)
487
+	s.Mod(s, p)
488
+	t.SetBytes(hashMPIs(h, 7, s, r))
489
+	if t.Cmp(cr) != 0 {
490
+		err = errors.New("otr: ZKP cR failed in SMP3 message")
491
+		return
492
+	}
493
+
494
+	var randBuf [16]byte
495
+	r7 := c.randMPI(randBuf[:])
496
+	rb := new(big.Int).Exp(qaqb, c.smp.b3, p)
497
+
498
+	r.Exp(qaqb, r7, p)
499
+	s.Exp(g, r7, p)
500
+	cr = new(big.Int).SetBytes(hashMPIs(h, 8, s, r))
501
+
502
+	r.Mul(c.smp.b3, cr)
503
+	d7 = new(big.Int).Sub(r7, r)
504
+	d7.Mod(d7, q)
505
+	if d7.Sign() < 0 {
506
+		d7.Add(d7, q)
507
+	}
508
+
509
+	out.typ = tlvTypeSMP4
510
+	out.data = appendU32(out.data, 3)
511
+	out.data = appendMPIs(out.data, rb, cr, d7)
512
+
513
+	r.ModInverse(c.smp.pb, p)
514
+	r.Mul(pa, r)
515
+	r.Mod(r, p)
516
+	s.Exp(ra, c.smp.b3, p)
517
+	if r.Cmp(s) != 0 {
518
+		err = smpFailureError
519
+	}
520
+
521
+	return
522
+}
523
+
524
+func (c *Conversation) processSMP4(mpis []*big.Int) error {
525
+	if len(mpis) != 3 {
526
+		return errors.New("otr: incorrect number of arguments in SMP4 message")
527
+	}
528
+	rb := mpis[0]
529
+	cr := mpis[1]
530
+	d7 := mpis[2]
531
+	h := sha256.New()
532
+
533
+	r := new(big.Int).Exp(c.smp.qaqb, d7, p)
534
+	s := new(big.Int).Exp(rb, cr, p)
535
+	r.Mul(r, s)
536
+	r.Mod(r, p)
537
+
538
+	s.Exp(g, d7, p)
539
+	t := new(big.Int).Exp(c.smp.g3b, cr, p)
540
+	s.Mul(s, t)
541
+	s.Mod(s, p)
542
+	t.SetBytes(hashMPIs(h, 8, s, r))
543
+	if t.Cmp(cr) != 0 {
544
+		return errors.New("otr: ZKP cR failed in SMP4 message")
545
+	}
546
+
547
+	r.Exp(rb, c.smp.a3, p)
548
+	if r.Cmp(c.smp.papb) != 0 {
549
+		return smpFailureError
550
+	}
551
+
552
+	return nil
553
+}
554
+
555
+func (c *Conversation) generateSMPAbort() tlv {
556
+	return tlv{typ: tlvTypeSMPAbort}
557
+}
558
+
559
+func hashMPIs(h hash.Hash, magic byte, mpis ...*big.Int) []byte {
560
+	if h != nil {
561
+		h.Reset()
562
+	} else {
563
+		h = sha256.New()
564
+	}
565
+
566
+	h.Write([]byte{magic})
567
+	for _, mpi := range mpis {
568
+		h.Write(appendMPI(nil, mpi))
569
+	}
570
+	return h.Sum(nil)
571
+}
0 572
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// Copyright 2012 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// Package test contains integration tests for the
5
+// golang.org/x/crypto/ssh package.
6
+package test // import "golang.org/x/crypto/ssh/test"
0 7
new file mode 100644
... ...
@@ -0,0 +1,173 @@
0
+// Copyright 2017 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// sshd_test_pw.c
5
+// Wrapper to inject test password data for sshd PAM authentication
6
+//
7
+// This wrapper implements custom versions of getpwnam, getpwnam_r,
8
+// getspnam and getspnam_r. These functions first call their real
9
+// libc versions, then check if the requested user matches test user
10
+// specified in env variable TEST_USER and if so replace the password
11
+// with crypted() value of TEST_PASSWD env variable.
12
+//
13
+// Compile:
14
+// gcc -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
15
+//
16
+// Compile with debug:
17
+// gcc -DVERBOSE -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
18
+//
19
+// Run sshd:
20
+// LD_PRELOAD="sshd_test_pw.so" TEST_USER="..." TEST_PASSWD="..." sshd ...
21
+
22
+// +build ignore
23
+
24
+#define _GNU_SOURCE
25
+#include <string.h>
26
+#include <pwd.h>
27
+#include <shadow.h>
28
+#include <dlfcn.h>
29
+#include <stdlib.h>
30
+#include <unistd.h>
31
+#include <stdio.h>
32
+
33
+#ifdef VERBOSE
34
+#define DEBUG(X...) fprintf(stderr, X)
35
+#else
36
+#define DEBUG(X...) while (0) { }
37
+#endif
38
+
39
+/* crypt() password */
40
+static char *
41
+pwhash(char *passwd) {
42
+  return strdup(crypt(passwd, "$6$"));
43
+}
44
+
45
+/* Pointers to real functions in libc */
46
+static struct passwd * (*real_getpwnam)(const char *) = NULL;
47
+static int (*real_getpwnam_r)(const char *, struct passwd *, char *, size_t, struct passwd **) = NULL;
48
+static struct spwd * (*real_getspnam)(const char *) = NULL;
49
+static int (*real_getspnam_r)(const char *, struct spwd *, char *, size_t, struct spwd **) = NULL;
50
+
51
+/* Cached test user and test password */
52
+static char *test_user = NULL;
53
+static char *test_passwd_hash = NULL;
54
+
55
+static void
56
+init(void) {
57
+  /* Fetch real libc function pointers */
58
+  real_getpwnam = dlsym(RTLD_NEXT, "getpwnam");
59
+  real_getpwnam_r = dlsym(RTLD_NEXT, "getpwnam_r");
60
+  real_getspnam = dlsym(RTLD_NEXT, "getspnam");
61
+  real_getspnam_r = dlsym(RTLD_NEXT, "getspnam_r");
62
+  
63
+  /* abort if env variables are not defined */
64
+  if (getenv("TEST_USER") == NULL || getenv("TEST_PASSWD") == NULL) {
65
+    fprintf(stderr, "env variables TEST_USER and TEST_PASSWD are missing\n");
66
+    abort();
67
+  }
68
+
69
+  /* Fetch test user and test password from env */
70
+  test_user = strdup(getenv("TEST_USER"));
71
+  test_passwd_hash = pwhash(getenv("TEST_PASSWD"));
72
+
73
+  DEBUG("sshd_test_pw init():\n");
74
+  DEBUG("\treal_getpwnam: %p\n", real_getpwnam);
75
+  DEBUG("\treal_getpwnam_r: %p\n", real_getpwnam_r);
76
+  DEBUG("\treal_getspnam: %p\n", real_getspnam);
77
+  DEBUG("\treal_getspnam_r: %p\n", real_getspnam_r);
78
+  DEBUG("\tTEST_USER: '%s'\n", test_user);
79
+  DEBUG("\tTEST_PASSWD: '%s'\n", getenv("TEST_PASSWD"));
80
+  DEBUG("\tTEST_PASSWD_HASH: '%s'\n", test_passwd_hash);
81
+}
82
+
83
+static int
84
+is_test_user(const char *name) {
85
+  if (test_user != NULL && strcmp(test_user, name) == 0)
86
+    return 1;
87
+  return 0;
88
+}
89
+
90
+/* getpwnam */
91
+
92
+struct passwd *
93
+getpwnam(const char *name) {
94
+  struct passwd *pw;
95
+
96
+  DEBUG("sshd_test_pw getpwnam(%s)\n", name);
97
+  
98
+  if (real_getpwnam == NULL)
99
+    init();
100
+  if ((pw = real_getpwnam(name)) == NULL)
101
+    return NULL;
102
+
103
+  if (is_test_user(name))
104
+    pw->pw_passwd = strdup(test_passwd_hash);
105
+      
106
+  return pw;
107
+}
108
+
109
+/* getpwnam_r */
110
+
111
+int
112
+getpwnam_r(const char *name,
113
+	   struct passwd *pwd,
114
+	   char *buf,
115
+	   size_t buflen,
116
+	   struct passwd **result) {
117
+  int r;
118
+
119
+  DEBUG("sshd_test_pw getpwnam_r(%s)\n", name);
120
+  
121
+  if (real_getpwnam_r == NULL)
122
+    init();
123
+  if ((r = real_getpwnam_r(name, pwd, buf, buflen, result)) != 0 || *result == NULL)
124
+    return r;
125
+
126
+  if (is_test_user(name))
127
+    pwd->pw_passwd = strdup(test_passwd_hash);
128
+  
129
+  return 0;
130
+}
131
+
132
+/* getspnam */
133
+
134
+struct spwd *
135
+getspnam(const char *name) {
136
+  struct spwd *sp;
137
+
138
+  DEBUG("sshd_test_pw getspnam(%s)\n", name);
139
+  
140
+  if (real_getspnam == NULL)
141
+    init();
142
+  if ((sp = real_getspnam(name)) == NULL)
143
+    return NULL;
144
+
145
+  if (is_test_user(name))
146
+    sp->sp_pwdp = strdup(test_passwd_hash);
147
+  
148
+  return sp;
149
+}
150
+
151
+/* getspnam_r */
152
+
153
+int
154
+getspnam_r(const char *name,
155
+	   struct spwd *spbuf,
156
+	   char *buf,
157
+	   size_t buflen,
158
+	   struct spwd **spbufp) {
159
+  int r;
160
+
161
+  DEBUG("sshd_test_pw getspnam_r(%s)\n", name);
162
+  
163
+  if (real_getspnam_r == NULL)
164
+    init();
165
+  if ((r = real_getspnam_r(name, spbuf, buf, buflen, spbufp)) != 0)
166
+    return r;
167
+
168
+  if (is_test_user(name))
169
+    spbuf->sp_pwdp = strdup(test_passwd_hash);
170
+  
171
+  return r;
172
+}
0 173
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// Package cpu implements processor feature detection for
5
+// various CPU architectures.
6
+package cpu
7
+
8
+// CacheLinePad is used to pad structs to avoid false sharing.
9
+type CacheLinePad struct{ _ [cacheLineSize]byte }
10
+
11
+// X86 contains the supported CPU features of the
12
+// current X86/AMD64 platform. If the current platform
13
+// is not X86/AMD64 then all feature flags are false.
14
+//
15
+// X86 is padded to avoid false sharing. Further the HasAVX
16
+// and HasAVX2 are only set if the OS supports XMM and YMM
17
+// registers in addition to the CPUID feature bit being set.
18
+var X86 struct {
19
+	_            CacheLinePad
20
+	HasAES       bool // AES hardware implementation (AES NI)
21
+	HasADX       bool // Multi-precision add-carry instruction extensions
22
+	HasAVX       bool // Advanced vector extension
23
+	HasAVX2      bool // Advanced vector extension 2
24
+	HasBMI1      bool // Bit manipulation instruction set 1
25
+	HasBMI2      bool // Bit manipulation instruction set 2
26
+	HasERMS      bool // Enhanced REP for MOVSB and STOSB
27
+	HasFMA       bool // Fused-multiply-add instructions
28
+	HasOSXSAVE   bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
29
+	HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
30
+	HasPOPCNT    bool // Hamming weight instruction POPCNT.
31
+	HasSSE2      bool // Streaming SIMD extension 2 (always available on amd64)
32
+	HasSSE3      bool // Streaming SIMD extension 3
33
+	HasSSSE3     bool // Supplemental streaming SIMD extension 3
34
+	HasSSE41     bool // Streaming SIMD extension 4 and 4.1
35
+	HasSSE42     bool // Streaming SIMD extension 4 and 4.2
36
+	_            CacheLinePad
37
+}
0 38
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+package cpu
5
+
6
+const cacheLineSize = 32
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+package cpu
5
+
6
+const cacheLineSize = 64
0 7
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+// +build !gccgo
6
+
7
+package cpu
8
+
9
+// cpuid is implemented in cpu_x86.s for gc compiler
10
+// and in cpu_gccgo.c for gccgo.
11
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
12
+
13
+// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler
14
+// and in cpu_gccgo.c for gccgo.
15
+func xgetbv() (eax, edx uint32)
0 16
new file mode 100644
... ...
@@ -0,0 +1,43 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+// +build gccgo
6
+
7
+#include <cpuid.h>
8
+#include <stdint.h>
9
+
10
+// Need to wrap __get_cpuid_count because it's declared as static.
11
+int
12
+gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf,
13
+                   uint32_t *eax, uint32_t *ebx,
14
+                   uint32_t *ecx, uint32_t *edx)
15
+{
16
+	return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx);
17
+}
18
+
19
+// xgetbv reads the contents of an XCR (Extended Control Register)
20
+// specified in the ECX register into registers EDX:EAX.
21
+// Currently, the only supported value for XCR is 0.
22
+//
23
+// TODO: Replace with a better alternative:
24
+//
25
+//     #include <xsaveintrin.h>
26
+//
27
+//     #pragma GCC target("xsave")
28
+//
29
+//     void gccgoXgetbv(uint32_t *eax, uint32_t *edx) {
30
+//       unsigned long long x = _xgetbv(0);
31
+//       *eax = x & 0xffffffff;
32
+//       *edx = (x >> 32) & 0xffffffff;
33
+//     }
34
+//
35
+// Note that _xgetbv is defined starting with GCC 8.
36
+void
37
+gccgoXgetbv(uint32_t *eax, uint32_t *edx)
38
+{
39
+	__asm("  xorl %%ecx, %%ecx\n"
40
+	      "  xgetbv"
41
+	    : "=a"(*eax), "=d"(*edx));
42
+}
0 43
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+// +build gccgo
6
+
7
+package cpu
8
+
9
+//extern gccgoGetCpuidCount
10
+func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32)
11
+
12
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) {
13
+	var a, b, c, d uint32
14
+	gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d)
15
+	return a, b, c, d
16
+}
17
+
18
+//extern gccgoXgetbv
19
+func gccgoXgetbv(eax, edx *uint32)
20
+
21
+func xgetbv() (eax, edx uint32) {
22
+	var a, d uint32
23
+	gccgoXgetbv(&a, &d)
24
+	return a, d
25
+}
0 26
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build mips64 mips64le
5
+
6
+package cpu
7
+
8
+const cacheLineSize = 32
0 9
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build mips mipsle
5
+
6
+package cpu
7
+
8
+const cacheLineSize = 32
0 9
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build ppc64 ppc64le
5
+
6
+package cpu
7
+
8
+const cacheLineSize = 128
0 9
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+package cpu
5
+
6
+const cacheLineSize = 256
0 7
new file mode 100644
... ...
@@ -0,0 +1,55 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+
6
+package cpu
7
+
8
+const cacheLineSize = 64
9
+
10
+func init() {
11
+	maxID, _, _, _ := cpuid(0, 0)
12
+
13
+	if maxID < 1 {
14
+		return
15
+	}
16
+
17
+	_, _, ecx1, edx1 := cpuid(1, 0)
18
+	X86.HasSSE2 = isSet(26, edx1)
19
+
20
+	X86.HasSSE3 = isSet(0, ecx1)
21
+	X86.HasPCLMULQDQ = isSet(1, ecx1)
22
+	X86.HasSSSE3 = isSet(9, ecx1)
23
+	X86.HasFMA = isSet(12, ecx1)
24
+	X86.HasSSE41 = isSet(19, ecx1)
25
+	X86.HasSSE42 = isSet(20, ecx1)
26
+	X86.HasPOPCNT = isSet(23, ecx1)
27
+	X86.HasAES = isSet(25, ecx1)
28
+	X86.HasOSXSAVE = isSet(27, ecx1)
29
+
30
+	osSupportsAVX := false
31
+	// For XGETBV, OSXSAVE bit is required and sufficient.
32
+	if X86.HasOSXSAVE {
33
+		eax, _ := xgetbv()
34
+		// Check if XMM and YMM registers have OS support.
35
+		osSupportsAVX = isSet(1, eax) && isSet(2, eax)
36
+	}
37
+
38
+	X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
39
+
40
+	if maxID < 7 {
41
+		return
42
+	}
43
+
44
+	_, ebx7, _, _ := cpuid(7, 0)
45
+	X86.HasBMI1 = isSet(3, ebx7)
46
+	X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
47
+	X86.HasBMI2 = isSet(8, ebx7)
48
+	X86.HasERMS = isSet(9, ebx7)
49
+	X86.HasADX = isSet(19, ebx7)
50
+}
51
+
52
+func isSet(bitpos uint, value uint32) bool {
53
+	return value&(1<<bitpos) != 0
54
+}
0 55
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+// +build !gccgo
6
+
7
+#include "textflag.h"
8
+
9
+// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
10
+TEXT ·cpuid(SB), NOSPLIT, $0-24
11
+	MOVL eaxArg+0(FP), AX
12
+	MOVL ecxArg+4(FP), CX
13
+	CPUID
14
+	MOVL AX, eax+8(FP)
15
+	MOVL BX, ebx+12(FP)
16
+	MOVL CX, ecx+16(FP)
17
+	MOVL DX, edx+20(FP)
18
+	RET
19
+
20
+// func xgetbv() (eax, edx uint32)
21
+TEXT ·xgetbv(SB),NOSPLIT,$0-8
22
+	MOVL $0, CX
23
+	XGETBV
24
+	MOVL AX, eax+0(FP)
25
+	MOVL DX, edx+4(FP)
26
+	RET