func (kx *KeyExchange) exchange1() error { reply, err := kx.meetingPlace.Exchange(kx.Log, kx.meeting1[:], kx.message1[:], kx.ShutdownChan) if err != nil { return err } var peerDHPublic, encryptedPeerDHPublic [32]byte if len(reply) < len(encryptedPeerDHPublic) { return errors.New("panda: meeting point reply too small") } copy(encryptedPeerDHPublic[:], reply) rijndael.NewCipher(&kx.key).Decrypt(&peerDHPublic, &encryptedPeerDHPublic) curve25519.ScalarMult(&kx.sharedKey, &kx.dhPrivate, &peerDHPublic) paddedLen := kx.meetingPlace.Padding() padded := make([]byte, paddedLen-24 /* nonce */ -secretbox.Overhead) binary.LittleEndian.PutUint32(padded, uint32(len(kx.kxBytes))) copy(padded[4:], kx.kxBytes) if _, err := io.ReadFull(kx.rand, padded[4+len(kx.kxBytes):]); err != nil { return err } var nonce [24]byte if _, err := io.ReadFull(kx.rand, nonce[:]); err != nil { return err } kx.message2 = make([]byte, paddedLen) copy(kx.message2, nonce[:]) secretbox.Seal(kx.message2[24:24], padded, &nonce, &kx.sharedKey) return nil }
func (kx *KeyExchange) derivePassword() error { serialised, err := proto.Marshal(kx.sharedSecret.toProto()) if err != nil { return err } if kx.Testing { h := sha256.New() h.Write([]byte{0}) h.Write(serialised) h.Sum(kx.key[:0]) h.Reset() h.Write([]byte{1}) h.Write(serialised) h.Sum(kx.meeting1[:0]) h.Reset() h.Write([]byte{2}) h.Write(serialised) h.Sum(kx.meeting2[:0]) } else { data, err := scrypt.Key(serialised, nil, 1<<17, 16, 4, 32*3) if err != nil { return err } copy(kx.key[:], data) copy(kx.meeting1[:], data[32:]) copy(kx.meeting2[:], data[64:]) } var encryptedDHPublic [32]byte rijndael.NewCipher(&kx.key).Encrypt(&encryptedDHPublic, &kx.dhPublic) l := len(encryptedDHPublic) if padding := kx.meetingPlace.Padding(); l > padding { return errors.New("panda: initial message too large for meeting place") } else if l < padding { l = padding } kx.message1 = make([]byte, l) copy(kx.message1, encryptedDHPublic[:]) if _, err := io.ReadFull(kx.rand, kx.message1[len(encryptedDHPublic):]); err != nil { return err } return nil }
func (kx *KeyExchange) derivePassword() error { serialised, err := proto.Marshal(kx.sharedSecret.toProto()) if err != nil { return err } if kx.Testing { h := sha256.New() h.Write([]byte{0}) h.Write(serialised) h.Sum(kx.key[:0]) h.Reset() h.Write([]byte{1}) h.Write(serialised) h.Sum(kx.meeting1[:0]) h.Reset() h.Write([]byte{2}) h.Write(serialised) h.Sum(kx.meeting2[:0]) } else { var data []byte if runtime.GOARCH == "386" && runtime.GOOS == "linux" { // We're having GC problems on 32-bit systems with the // scrypt allocation. In order to help the GC out, the // scrypt computation is done in a subprocess. cmd := exec.Command("/proc/self/exe", "--panda-scrypt") var in, out bytes.Buffer binary.Write(&in, binary.LittleEndian, uint32(len(serialised))) in.Write(serialised) cmd.Stdin = &in cmd.Stdout = &out cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return err } data = out.Bytes() if len(data) != 32*3 { return errors.New("scrypt subprocess returned wrong number of bytes: " + strconv.Itoa(len(data))) } } else { if data, err = scrypt.Key(serialised, nil, 1<<17, 16, 4, 32*3); err != nil { return err } } copy(kx.key[:], data) copy(kx.meeting1[:], data[32:]) copy(kx.meeting2[:], data[64:]) } var encryptedDHPublic [32]byte rijndael.NewCipher(&kx.key).Encrypt(&encryptedDHPublic, &kx.dhPublic) l := len(encryptedDHPublic) if padding := kx.meetingPlace.Padding(); l > padding { return errors.New("panda: initial message too large for meeting place") } else if l < padding { l = padding } kx.message1 = make([]byte, l) copy(kx.message1, encryptedDHPublic[:]) if _, err := io.ReadFull(kx.rand, kx.message1[len(encryptedDHPublic):]); err != nil { return err } return nil }