Example #1
0
// GetGlobalIndex returns the global index.
func (ms MessageServer) GetGlobalIndex(w http.ResponseWriter, r *http.Request) {
	var pubKey *message.Curve25519Key
	start := int64(0)
	count := int64(10)
	w.Header().Set("Content-Type", "text/plain; charset=us-ascii")
	getValues := r.URL.Query()
	if getValues != nil {
		if v, ok := getValues["start"]; ok {
			t, err := strconv.Atoi(v[0])
			if err == nil {
				start = int64(t)
			}
		}
		if v, ok := getValues["count"]; ok {
			t, err := strconv.Atoi(v[0])
			if err == nil {
				count = int64(t)
				if count > ms.MaxIndexGlobal {
					count = ms.MaxIndexGlobal
				}
			}
		}
		if v, ok := getValues["auth"]; ok {
			err := ms.AuthenticatePeer(v[0])
			if err != nil {
				io.WriteString(w, fmt.Sprintf("Error: %s", err))
				return
			}
		} else {
			io.WriteString(w, "ERROR: Missing param\n")
			return
		}
	} else {
		io.WriteString(w, "ERROR: Missing param\n")
		return
	}
	messages, found, err := ms.DB.GetGlobalIndex(start, count)
	if err != nil && err != ErrNoMore {
		log.Debugf("List:GetIndex: %s\n", err)
		log.Debugf("List:GetIndex: Key %s\n", utils.B58encode(pubKey[:]))
		io.WriteString(w, "ERROR: List failed\n")
		return
	}
	io.WriteString(w, "SUCCESS: Data follows\n")
	for _, msg := range messages {
		io.WriteString(w, "IDX: "+strings.Trim(string(msg), " \t\n\r")+"\n")
	}
	if int64(found) < count {
		io.WriteString(w, "CMD: Exceeded\n")
	} else {
		io.WriteString(w, "CMD: Continue\n")
	}
}
Example #2
0
// FetchPost fetches a post from a peer and adds it.
func (ms MessageServer) FetchPost(url, auth string, msgID [message.MessageIDSize]byte, expireRequest uint64) error {
	// Fetch the post
	proto := repproto.New(ms.SocksProxy, "")
	data, err := proto.GetSpecificAuth(url, auth, msgID[:])
	// data, err := proto.GetSpecific(url, msgID[:])
	if err != nil {
		return err
	}
	// Verify and use it
	signheader, err := message.Base64Message(data).GetSignHeader()
	if err != nil {
		log.Debugf("Bad fetch:GetSignHeader: %s\n", err)
		return err
	}
	details, err := message.VerifySignature(*signheader, ms.MinHashCashBits)
	if err != nil {
		log.Debugf("Bad fetch:VerifySignature: %s\n", err)
		return err
	}
	constantRecipientPub, MessageID, err := deferVerify(data)
	if err != nil {
		log.Debugf("Bad fetch:deferVerify: %s\n", err)
		return err
	}
	if *MessageID != details.MsgID {
		log.Debugs("Bad fetch:MessageID\n")
		return ErrBadMessageID
	}
	msgStruct := &structs.MessageStruct{
		MessageID:              *MessageID,
		ReceiverConstantPubKey: *constantRecipientPub,
		SignerPub:              details.PublicKey,
		OneTime:                false,
		Sync:                   false,
		Hidden:                 false,
		ExpireRequest:          expireRequest,
	}
	if message.KeyIsSync(constantRecipientPub) {
		msgStruct.Sync = true
	}
	if message.KeyIsHidden(constantRecipientPub) {
		msgStruct.Hidden = true
	}

	sigStruct := &structs.SignerStruct{
		PublicKey: details.PublicKey,
		Nonce:     details.HashCashNonce,
		Bits:      details.HashCashBits,
	}
	sigStruct.MaxMessagesPosted, sigStruct.MaxMessagesRetained, sigStruct.ExpireTarget = ms.calcLimits(details.HashCashBits)
	return ms.DB.Put(msgStruct, sigStruct, data)
}
Example #3
0
// Fetch returns a single message.
func (ms MessageServer) Fetch(w http.ResponseWriter, r *http.Request) {
	var messageID *[message.MessageIDSize]byte
	w.Header().Set("Content-Type", "text/plain; charset=us-ascii")
	getValues := r.URL.Query()
	if getValues != nil {
		if v, ok := getValues["messageid"]; ok {
			t := utils.B58decode(v[0])
			if len(t) < message.MessageIDSize || len(t) > message.MessageIDSize {
				io.WriteString(w, "ERROR: Bad parameter\n")
				return
			}
			messageID = new([message.MessageIDSize]byte)
			copy(messageID[:], t)
		}
		if ms.HubOnly {
			if v, ok := getValues["auth"]; ok {
				err := ms.AuthenticatePeer(v[0])
				if err != nil {
					io.WriteString(w, fmt.Sprintf("Error: %s", err))
					return
				}
			} else {
				io.WriteString(w, "ERROR: Missing param\n")
				return
			}
		}
	}
	if messageID == nil {
		io.WriteString(w, "ERROR: Missing parameter\n")
		return
	}
	data, err := ms.DB.Fetch(messageID)
	if err != nil {
		log.Debugf("Fetch: %s\n", err)
		io.WriteString(w, "ERROR: No data")
		return
	}
	io.WriteString(w, "SUCCESS: Data follows\n")
	_, err = w.Write(data)
	if err != nil {
		log.Debugf("Write: %s\n", err)
		return
	}
	log.Debugs("Fetch OK\n")
	if ms.Stat {
		stat.Input <- stat.Fetch
	}
	return
}
Example #4
0
// ServeID returns server information.
func (ms MessageServer) ServeID(w http.ResponseWriter, r *http.Request) {
	ms.RandomSleep()
	now := CurrentTime() + ms.TimeSkew
	privK := [32]byte(*ms.authPrivKey)
	_, pubkey, challenge := keyauth.GenTempKeyTime(uint64(now), &privK)
	info := &ServerInfo{
		Time:            now,
		AuthPubKey:      utils.B58encode(pubkey[:]),
		AuthChallenge:   utils.B58encode(challenge[:]),
		MaxPostSize:     int64(messagestore.MaxMessageSize),
		MinPostSize:     ms.InfoStruct.MinPostSize,
		MinHashCashBits: ms.InfoStruct.MinHashCashBits,
	}
	if ms.EnablePeerHandler {
		info.Peers = ms.getPeerURLs()
	}
	ms.RandomSleep()
	w.Header().Set("Content-Type", "text/json")
	b, err := json.Marshal(info)
	if err != nil {
		log.Debugf("Info: %s\n", err)
	}
	w.Write(b)
	w.Write([]byte("\n"))
	return
}
Example #5
0
// ExpireFromIndex reads the expire index and expires messages as they are recorded
func (store Store) ExpireFromIndex(cycles int) {
	// run from now backwards N cycles
	now := uint64(time.Now().Unix())
	expireTime := (now / uint64(ExpireRun))
	for i := cycles; i > 0; i-- {
		expireTime -= uint64(ExpireRun)
		log.Debugf("Expire index try: %d\n", expireTime)
		if expireTime > 0 {
			if store.expireindex.Index(utils.EncodeUInt64(expireTime)).Exists() {
				j := int64(0)
				log.Debugf("Expire index found: %d\n", expireTime)
			ExpireEntries:
				for {
					entry, err := store.expireindex.Index(utils.EncodeUInt64(expireTime)).ReadEntry(j)
					if err != nil { // no more entries
						log.Debugf("Expire index empty: %d\n", expireTime)
						break ExpireEntries
					}
					j++
					if entry == nil {
						log.Debugf("Expire index bad entry: %d %d\n", j, expireTime)
						continue // bad entry
					}
					entryStruct := structs.ExpireStructDecode(entry)
					if entryStruct == nil {
						log.Debugf("Expire index bad entry decode: %d %d\n", j, expireTime)
						continue // bad entry
					}
					if entryStruct.ExpireTime > now {
						log.Debugf("Expire index bad entry not expired: %d %d\n", j, expireTime)
						continue // bad entry
					}
					store.messages.Index(entryStruct.MessageID[:]).Delete() // Delete message
					store.signers.Index(entryStruct.SignerPubKey[:]).Update(func(tx fileback.Tx) error {
						data := tx.GetLast()
						if data == nil { // we don't care about errors here
							return nil
						}
						signer := structs.SignerStructDecode(data)
						if signer == nil {
							return nil
						}
						signer.MessagesRetained--
						tx.Append(signer.Encode().Fill())
						return nil
					})
				}
				// Remove expire list
				store.expireindex.Index(utils.EncodeUInt64(expireTime)).Delete()
				log.Debugf("Expire index deleted: %d\n", expireTime)
			} else {
				log.Debugf("Expire index does not exist: %d\n", expireTime)
			}
		}
	}
}
Example #6
0
func (store Store) expireSigners() {
	//s.signers = fileback.NewRoundRobin(dir+signerDir, structs.SignerStructSize, 10, ' ', []byte("\n"), workers)       // We keep signer history, last 10 entries
	now := time.Now().Unix()
	indices := store.signers.Indices()
	if indices == nil {
		log.Debugs("ExpireFS: No signers\n")
		return
	}
	for _, signer := range indices {
		last := store.signers.Index(signer).LastChange(0)
		if last != 0 && last < now-int64(FSExpire) {
			store.signers.Index(signer).Truncate() // We don't delete for real, otherwise the signer would become reusable.
			log.Debugf("ExpireFS: Signer truncated %x\n", signer)
		} else {
			log.Debugf("ExpireFS: Signer remains %x\n", signer)
		}
	}
}
Example #7
0
func (store Store) expireKeyIndices() {
	//s.keyindex = fileback.NewRolling(dir+keyindexDir, structs.MessageStructSize, 2048, ' ', []byte("\n"), workers)    // Maximum 2048 entries per file
	now := time.Now().Unix()
	indices := store.keyindex.Indices()
	if indices == nil {
		log.Debugs("ExpireFS: No Key Indices\n")
		return
	}
	for _, keylist := range indices {
		entry := store.signers.Index(keylist)
		last := entry.LastChange(0)
		if last != 0 && last < now-int64(FSExpire) {
			// go forward
			lastEntry := entry.Entries() - 1
			if lastEntry >= 0 {
				last := entry.LastChange(lastEntry)
				if last < now-int64(FSExpire) {
					log.Debugf("ExpireFS: Key Index complete delete %x\n", keylist)
					entry.Delete() // Key lists are deleted
				} else {
					maxEntries := entry.MaxEntries()
					deleteBefore := int64(-1)
				LastLoop:
					for pos := lastEntry; pos > 0; pos = pos - maxEntries { // Search the first entry that has expired
						last := entry.LastChange(pos)
						if last != 0 && last < now-int64(FSExpire) {
							break LastLoop
						}
						deleteBefore = pos - 1 // This will actually skip the last expired object
					}
					if deleteBefore >= 0 {
						log.Debugf("ExpireFS: Key Index delete before %d %x\n", deleteBefore, keylist)
						entry.DeleteBefore(deleteBefore)
					} else {
						log.Debugf("ExpireFS: Key Index no delete match %x\n", keylist)
					}
				}
			}
		} else {
			log.Debugf("ExpireFS: Key Index remains %x\n", keylist)
		}
	}
}
Example #8
0
// GetNotify receives notifications.
func (ms MessageServer) GetNotify(w http.ResponseWriter, r *http.Request) {
	var proof [keyproof.ProofTokenSize]byte
	w.Header().Set("Content-Type", "text/plain; charset=us-ascii")
	getValues := r.URL.Query()
	if getValues != nil {
		if v, ok := getValues["auth"]; ok {
			if len(v[0]) > keyproof.ProofTokenMax {
				io.WriteString(w, "ERROR: Bad Param\n")
				return
			}
			auth := utils.B58decode(v[0])
			if auth == nil || len(auth) > keyproof.ProofTokenSize {
				io.WriteString(w, "ERROR: Bad Param\n")
				return
			}
			copy(proof[:], auth)
			ok, timeStamp, senderPubKey := keyproof.VerifyProofToken(&proof, ms.TokenPubKey)
			if !ok {
				io.WriteString(w, "ERROR: Authentication failure\n")
				if senderPubKey == nil {
					log.Errorf("VerifyProofToken failed: (proof) %s\n", utils.B58encode(proof[:]))
				} else {
					log.Errorf("VerifyProofToken failed: (pubkey) %s\n", utils.B58encode(senderPubKey[:]))
				}
				return
			}
			// verify that we know the peer
			url := ms.PeerURL(senderPubKey)
			if url == "" {
				io.WriteString(w, "ERROR: Bad peer\n")
				log.Errorf("Notify, bad peer: %s\n", utils.B58encode(senderPubKey[:]))
				return
			}
			now := CurrentTime()
			// Test too old, too young
			if enforceTimeOuts && (now > timeStamp+DefaultAuthTokenAge+ms.MaxTimeSkew || now < timeStamp-DefaultAuthTokenAge-ms.MaxTimeSkew) {
				io.WriteString(w, "ERROR: Authentication expired\n")
				log.Errorf("VerifyProofToken replay by %s\n", url)
				return
			}
			ok, signedToken := keyproof.CounterSignToken(&proof, ms.TokenPubKey, ms.TokenPrivKey)
			if !ok {
				io.WriteString(w, "ERROR: Authentication failure\n")
				return
			}
			ms.DB.UpdatePeerAuthToken(senderPubKey, signedToken)
			log.Debugf("Notified by %s\n", url)
			io.WriteString(w, "SUCCESS: Notified\n")
			return
		}
	}
	io.WriteString(w, "ERROR: Missing Param\n")
	return
}
Example #9
0
func (ms MessageServer) notifyPeer(PubKey *[ed25519.PublicKeySize]byte, url string) {
	rand.Seed(time.Now().UnixNano())
	maxSleep := ms.NotifyDuration - int64(timeout)
	if maxSleep > 0 {
		sleeptime := rand.Int63() % maxSleep
		time.Sleep(time.Duration(sleeptime) * time.Second)
	}
	now := CurrentTime() + ms.TimeSkew
	token := utils.B58encode(keyproof.SignProofToken(now, PubKey, ms.TokenPubKey, ms.TokenPrivKey)[:])
	// Socks call
	proto := repproto.New(ms.SocksProxy, "")
	err := proto.Notify(url, token)
	// Write result
	if err != nil {
		log.Debugf("Notify error: %s\n", err)
		ms.DB.UpdatePeerNotification(PubKey, true)
	} else {
		log.Debugf("Notified peer: %s\n", url)
		ms.DB.UpdatePeerNotification(PubKey, false)
	}
}
Example #10
0
// RunServer starts the HTTP handlers.
func (ms MessageServer) RunServer() {
	ts, err := rand.Int(rand.Reader, big.NewInt(ms.MaxTimeSkew))
	if err != nil {
		panic(err)
	}
	ms.TimeSkew = ts.Int64()
	log.Debugf("TimeSkew: %d\n", ms.TimeSkew)

	// Peering
	ms.notifyChan = make(chan bool, 3)
	// Load peers
	ms.LoadPeers()
	// Start statistics goroutine
	if ms.Stat {
		go stat.Run()
	}
	// Start timers
	go ms.notifyWatch()
	// static file handler
	httpHandlers := http.NewServeMux()

	httpHandlers.Handle("/", http.FileServer(http.Dir(ms.path+string(os.PathSeparator)+"static")))
	httpHandlers.HandleFunc("/id", ms.ServeID)
	if !ms.HubOnly {
		httpHandlers.HandleFunc("/keyindex", ms.GetKeyIndex)
		httpHandlers.HandleFunc("/post", ms.GenPostHandler(false))
		if ms.EnableOneTimeHandler {
			httpHandlers.HandleFunc("/local/post", ms.GenPostHandler(true))
		}
		if ms.EnableDeleteHandler {
			httpHandlers.HandleFunc("/delete", ms.Delete)
		}
	}
	httpHandlers.HandleFunc("/globalindex", ms.GetGlobalIndex)
	httpHandlers.HandleFunc("/fetch", ms.Fetch)
	httpHandlers.HandleFunc("/notify", ms.GetNotify)
	httpServer := &http.Server{
		Addr:           "127.0.0.1:" + strconv.Itoa(ms.ListenPort),
		Handler:        httpHandlers,
		ReadTimeout:    90 * time.Second,
		WriteTimeout:   90 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	httpServer.ListenAndServe()
}
Example #11
0
// DecryptBody decrypts a body and verifies the hmac.
func (bd *DecryptBodyDef) DecryptBody(data []byte) ([]byte, byte, error) {
	var content []byte
	log.Secretf("Shared Secret: %x\n", bd.SharedSecret)
	hmacKey, symmetricKey := CalcKeys(bd.SharedSecret)
	log.Secretf("HMAC Key: %x\n", *hmacKey)
	log.Secretf("Symmetric Key: %x\n", *symmetricKey)
	hmaccalc := hmac.New(sha256.New, hmacKey[:])
	hmaccalc.Write(data[:len(data)-HMACSize])
	hmaccalcSum := hmaccalc.Sum(nil)
	if !hmac.Equal(hmaccalcSum, data[len(data)-HMACSize:]) {
		log.Debugf("Bad HMAC: %x\n", hmaccalcSum)
		return nil, 0, ErrBadHMAC
	}
	blockcipher, err := aes.NewCipher(symmetricKey[:])
	if err != nil {
		return nil, 0, err
	}
	ctr := cipher.NewCTR(blockcipher, bd.IV[:aes.BlockSize])
	// Calculate size of first read. Read one block unless message is too short
	firstRead := aes.BlockSize
	if len(data)-HMACSize < aes.BlockSize {
		firstRead = len(data)
	}
	header := make([]byte, firstRead)
	ctr.XORKeyStream(header, data[:firstRead])
	msgType := header[0]                                             // Decode Message Type
	length := binary.BigEndian.Uint16(header[1:encryptedHeaderSize]) // Decode Message Length
	log.Secretf("Real Length: %d\n", length)
	// Length escapes one block (minus header which is not part of the length)
	if length > aes.BlockSize-encryptedHeaderSize {
		// We have already read aes.BlockSize, but it includes the header
		nlength := length - aes.BlockSize + encryptedHeaderSize
		content = make([]byte, nlength)
		// Decrypt whatever is left
		ctr.XORKeyStream(content, data[aes.BlockSize:aes.BlockSize+nlength])
	}
	// Concat both reads
	content = append(header, content...)
	// Only return after header til end of message
	return content[encryptedHeaderSize : length+encryptedHeaderSize], msgType, nil
}
Example #12
0
func getPeers(force bool) error {
	log.Debugf("Peer update called. Last: %d\n", GlobalConfigVar.PeerUpdate)
	if GlobalConfigVar.PeerUpdate == 0 || GlobalConfigVar.PeerUpdate < (time.Now().Unix()-PeerUpdateDuration) {
		log.Debugs("Peer update forced. Prevent by running -peerlist.\n")
		force = true
	}
	if force {
		log.Debugs("Updating peers.\n")
		defer log.Debugs("Peer update done.\n")
		GlobalConfigVar.PeerUpdate = time.Now().Unix()
		server := OptionsVar.Server
		if server == "" && GlobalConfigVar.PasteServers != nil && len(GlobalConfigVar.PasteServers) > 0 { // no server defined, we select one
			servercount := len(GlobalConfigVar.PasteServers)
			rand.Seed(time.Now().UnixNano())
			pos := rand.Int() % servercount
			server = GlobalConfigVar.PasteServers[pos]
		}
		if server == "" {
			server = GlobalConfigVar.BootStrapPeer
		}
		if server == "" {
			return ErrNoPeers
		}
		proto := repproto.New(OptionsVar.Socksserver, OptionsVar.Server, GlobalConfigVar.PasteServers...)
		serverInfo, err := proto.ID(server)
		if err != nil {
			return ErrNoPeers
		}
		if serverInfo.Peers != nil && len(serverInfo.Peers) > 0 {
			GlobalConfigVar.PasteServers = serverInfo.Peers
			GlobalConfigVar.MinHashCash = serverInfo.MinHashCashBits
			err := WriteConfigFile(GlobalConfigVar)
			if err != nil {
				log.Errorf("Error writing config-file: %s\n", err)
			}
		}
	}
	return nil
}
Example #13
0
// fetchPeer downloads new messages from peer.
func (ms MessageServer) fetchPeer(PubKey *[ed25519.PublicKeySize]byte, url string) {
	// Get token, lastpos from database
	var doUpdate bool
	log.Debugf("fetch from peer: %s\n", url)
	peerStat := ms.DB.GetPeerStat(PubKey)
	if peerStat == nil { // Errors are ignored
		log.Debugf("fetch from peer: not found %s\n", url)
		return
	}
	if peerStat.LastNotifyFrom == 0 { // We never heard from him
		log.Debugf("fetch from peer: no notification %s\n", url)
		return
	}
	startDate := CurrentTime()
	// Check that LastNotifyFrom > LastFetch
	if ms.HubOnly {
		// Pre-Emptive fetch in hub-mode: every 4 times FetchDuration or when notified
		if peerStat.LastFetch != 0 && !(peerStat.LastFetch < peerStat.LastNotifyFrom || peerStat.LastFetch < uint64(startDate-(ms.FetchDuration*4))) {
			log.Debugf("fetch from peer: no fetch-force and no notifications since last fetch %s\n", url)
			log.Debugf("LastFetch: %s  LastNotifyFrom: %s\n", format(peerStat.LastFetch), format(peerStat.LastNotifyFrom))
			return // nothing new to gain
		}
	} else {
		if peerStat.LastFetch > peerStat.LastNotifyFrom && peerStat.LastFetch != 0 {
			log.Debugf("fetch from peer: no notifications since last fetch %s\n", url)
			log.Debugf("LastFetch: %s  LastNotifyFrom: %s\n", format(peerStat.LastFetch), format(peerStat.LastNotifyFrom))
			return // nothing new to gain
		}
	}
	rand.Seed(time.Now().UnixNano())
	maxSleep := ms.NotifyDuration - int64(timeout)
	if maxSleep > 0 {
		sleeptime := rand.Int63() % maxSleep
		log.Debugf("fetch from peer: sleeping %d %s\n", sleeptime, url)
		time.Sleep(time.Duration(sleeptime) * time.Second)
	}
	doUpdate = true
FetchLoop:
	for {
		// Make GetIndex call
		proto := repproto.New(ms.SocksProxy, "")
		nextPosition := int(peerStat.LastPosition)
		if nextPosition != 0 {
			nextPosition++
		}
		log.Debugf("GlobalIndex fetch: %s next: %d max: %d\n", url, nextPosition, ms.FetchMax)
		authtoken := utils.B58encode(peerStat.AuthToken[:])
		messages, more, err := proto.GetGlobalIndex(url, authtoken, nextPosition, int(ms.FetchMax))
		if err != nil {
			peerStat.ErrorCount++
			log.Debugf("GlobalIndex err: %s\n", err)
			// Only hit on proxy errors
			errstr := err.Error()
			if len(errstr) >= 6 && errstr[0:6] == "proxy:" {
				doUpdate = false
			}
			break FetchLoop
		}
		for _, msg := range messages {
			log.Debugf("Index: %d  Message: %s\n", msg.Counter, utils.B58encode(msg.MessageID[:]))
		}
	MessageLoop:
		for _, msg := range messages {
			log.Debugf("Fetching.  %d  %s\n", msg.Counter, utils.B58encode(msg.MessageID[:]))
			if startDate+ms.FetchDuration <= CurrentTime() { // We worked for long enough
				log.Debugf("FetchDuration timeout\n")
				break MessageLoop
			}
			// Check if message exists
			if ms.DB.MessageExists(msg.MessageID) {
				peerStat.LastPosition = msg.Counter
				log.Debugf("fetch from peer: exists %s %s\n", utils.B58encode(msg.MessageID[:]), url)
				continue MessageLoop // Message exists.
			}
			// Add message
			err := ms.FetchPost(url, authtoken, msg.MessageID, msg.ExpireTime)
			if err == nil || err == messagestore.ErrDuplicate {
				// Reduce fetch.ErrorCount when downloads are successful
				log.Debugf("fetch from peer: exists now %s %s\n", utils.B58encode(msg.MessageID[:]), url)
				if peerStat.ErrorCount >= 2 {
					peerStat.ErrorCount -= 2
				}
			} else if err != nil {
				peerStat.ErrorCount++
				log.Debugf("Fetch err: %s %s\n", url, err)
				doUpdate = false
				// LastPosition will only advance if future downloads work
				continue MessageLoop
			}
			log.Debugf("fetch from peer: added %s %s\n", utils.B58encode(msg.MessageID[:]), url)
			peerStat.LastPosition = msg.Counter
			ms.notifyChan <- true
		}
		if !more { // No more messages
			log.Debugf("Sync done. No More.\n")
			break FetchLoop
		}
		if startDate+ms.FetchDuration <= CurrentTime() { // We worked for long enough
			log.Debugf("Sync done. FetchDuration timeout.\n")
			break FetchLoop
		}
	}
	// Write peer update
	log.Debugf("fetch from peer: cycle done %s\n", url)
	if doUpdate {
		ms.DB.UpdatePeerFetchStat(PubKey, uint64(CurrentTime()), peerStat.LastPosition, peerStat.ErrorCount)
	} else {
		ms.DB.UpdatePeerFetchStat(PubKey, peerStat.LastFetch, peerStat.LastPosition, peerStat.ErrorCount)
	}
}
Example #14
0
// CmdEncrypt encrypts data.
func CmdEncrypt() int {
	var privkey, embedConstantPrivKey, embedTemporaryPrivKey, embedConstantPubKey, embedTemporaryPubKey *message.Curve25519Key
	var err error
	var inData, encMessage []byte
	var meta *message.MetaDataSend
	var signKeyPair *message.SignKeyPair
	var removeFile string
	if OptionsVar.Server == "" {
		getPeers(false)
	}
	// 	OptionsVar.anonymous . disable private key and signkey
	if OptionsVar.Anonymous {
		OptionsVar.Signkey = ""
		OptionsVar.Privkey = ""
		GlobalConfigVar.PrivateKey = ""
	}
	mindelay := uint32(OptionsVar.Mindelay)
	maxdelay := uint32(OptionsVar.Maxdelay)

	// Read input data
	maxInData := int64(GlobalConfigVar.BodyLength - (message.Curve25519KeySize * 2) - innerHeader)
	//maxInData := int64(MsgSizeLimit)
	if OptionsVar.Repost {
		maxInData -= utils.RepostHeaderSize - message.KeyHeaderSize - message.SignHeaderSize
	}
	log.Debugf("Size limit: %d\n", maxInData)
	inData, err = inputData(OptionsVar.Infile, maxInData)
	if err != nil {
		log.Fatalf("No input data: %s\n", err)
		return 1
	}

	// Verify list contents
	if OptionsVar.MessageType == message.MsgTypeList {
		err := utils.VerifyListContent(inData)
		if err != nil {
			log.Errorf("Could not verify list input: %s\n", err)
			return 1
		}
	}

	// Select private key to use
	privkeystr := selectPrivKey(OptionsVar.Privkey, GlobalConfigVar.PrivateKey, "")
	// Parse privkey
	if privkeystr != "" {
		privkey = new(message.Curve25519Key)
		copy(privkey[:], utils.B58decode(privkeystr))
	}
	// Generate embedded keypairs
	if OptionsVar.Embedkey {
		if OptionsVar.Notrace || privkey == nil {
			embedConstantPrivKey, err = message.GenLongTermKey(OptionsVar.Hidden, OptionsVar.Sync)
			if err != nil {
				log.Errorf("Key generation error:%s\n", err)
				return 1
			}
		} else {
			embedConstantPrivKey = privkey
		}
		embedConstantPubKey = message.GenPubKey(embedConstantPrivKey)
		embedTemporaryPrivKey, err = message.GenRandomKey()
		if err != nil {
			log.Errorf("Key generation error:%s\n", err)
			return 1
		}
		embedTemporaryPubKey = message.GenPubKey(embedTemporaryPrivKey)
	}
	embedded := utils.EncodeEmbedded(embedConstantPubKey, embedTemporaryPubKey)
	recipientConstantPubKey, recipientTemporaryPubKey := utils.ParseKeyPair(OptionsVar.Recipientkey)

	// Find a signature keypair if we can
	signKeyDir := ""
	if GlobalConfigVar.KeyDir != "" {
		signKeyDir = GlobalConfigVar.KeyDir
	}
	if OptionsVar.Signdir != "" {
		signKeyDir = OptionsVar.Signdir
	}

	if OptionsVar.Signkey != "" {
		var d []byte
		d, err = utils.MaxReadFile(2048, OptionsVar.Signkey)
		if err == nil {
			signKeyPair = new(message.SignKeyPair)
			kp, err := signKeyPair.Unmarshal(d)
			if err != nil {
				log.Errorf("Sign keypair decode error: %s\n", err)
				signKeyPair = nil
			} else {
				signKeyPair = kp
			}
		} else {
			log.Errorf("Sign keypair read error: %s\n", err)
		}
	}
	if signKeyPair == nil && signKeyDir != "" {
		var d []byte
		d, removeFile, err = utils.ReadRandomFile(signKeyDir, 2048)
		if err == nil {
			signKeyPair = new(message.SignKeyPair)
			kp, err := signKeyPair.Unmarshal(d)
			if err != nil {
				log.Errorf("Sign keypair decode error: %s\n", err)
				signKeyPair = nil
				removeFile = ""
			} else {
				signKeyPair = kp
			}
		} else {
			log.Errorf("Sign keypair read error: %s\n", err)
		}
	}

	// Set up sender parameters
	sender := message.Sender{
		Signer:                    signKeyPair,
		SenderPrivateKey:          privkey,
		ReceiveConstantPublicKey:  recipientConstantPubKey,
		ReceiveTemporaryPublicKey: recipientTemporaryPubKey,
		TotalLength:               GlobalConfigVar.BodyLength,
		PadToLength:               GlobalConfigVar.PadToLength,
		HashCashBits:              GlobalConfigVar.MinHashCash,
	}
	// We want encryption output in realtime
	log.Sync()
	inData = append(embedded, inData...)
	if OptionsVar.Repost {
		// Generate a repost-message
		encMessage, meta, err = sender.EncryptRepost(byte(OptionsVar.MessageType), inData)
		if err == nil {
			rph := utils.EncodeRepostHeader(meta.PadKey, mindelay, maxdelay)
			encMessage = append(rph[:], encMessage...)
			log.Datas("STATUS (Process):\tPREPOST\n")
			log.Dataf("STATUS (RepostSettings):\t%d %d\n", mindelay, maxdelay)
		}
	} else {
		// Generate a normal message
		encMessage, meta, err = sender.Encrypt(byte(OptionsVar.MessageType), inData)
		if err == nil {
			log.Datas("STATUS (Process):\tPOST\n")
		}
	}
	if err != nil {
		log.Fatalf("Encryption failed: %s\n", err)
		return 1
	}
	log.Sync()

	// Output. repost is only written to stdout or file
	if OptionsVar.Outfile == "-" || (OptionsVar.Repost && OptionsVar.Outfile == "") {
		err = utils.WriteStdout(encMessage)
		// Display data as necessary
		if err == nil {
			log.Dataf("STATUS (RecPubKey):\t%s\n", utils.B58encode(meta.ReceiverConstantPubKey[:]))
			if OptionsVar.Embedkey {
				log.Dataf("STATUS (EmbedPublicKey):\t%s_%s\n", utils.B58encode(embedConstantPubKey[:]), utils.B58encode(embedTemporaryPubKey[:]))
				log.Dataf("STATUS (EmbedPrivateKey):\t%s_%s\n", utils.B58encode(embedConstantPrivKey[:]), utils.B58encode(embedTemporaryPrivKey[:]))
			}
			if meta.MessageKey != nil {
				log.Dataf("STATUS (ListInput):\tNULL %s %s\n", utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
				log.Dataf("STATUS (Message):\t%s_%s\n", utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
			} else {
				log.Dataf("STATUS (ListInput):\tNULL %s NULL\n", utils.B58encode(meta.MessageID[:]))
				log.Dataf("STATUS (MessageID):\t%s\n", utils.B58encode(meta.MessageID[:]))
			}
		}
	} else if OptionsVar.Outfile != "" || OptionsVar.Repost {
		err = utils.WriteNewFile(OptionsVar.Outfile, encMessage)
		// Display data as necessary
		log.Dataf("STATUS (RecPubKey):\t%s\n", utils.B58encode(meta.ReceiverConstantPubKey[:]))
		if err == nil {
			if OptionsVar.Embedkey {
				log.Dataf("STATUS (EmbedPublicKey):\t%s_%s\n", utils.B58encode(embedConstantPubKey[:]), utils.B58encode(embedTemporaryPubKey[:]))
				log.Dataf("STATUS (EmbedPrivateKey):\t%s_%s\n", utils.B58encode(embedConstantPrivKey[:]), utils.B58encode(embedTemporaryPrivKey[:]))
			}
			if meta.MessageKey != nil {
				log.Dataf("STATUS (ListInput):\tNULL %s %s\n", utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
				log.Dataf("STATUS (Message):\t%s_%s\n", utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
				log.Printf("Pastebin Address:\t%s_%s\n", utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
			} else {
				log.Dataf("STATUS (ListInput):\tNULL %s NULL\n", utils.B58encode(meta.MessageID[:]))
				log.Dataf("STATUS (MessageID):\t%s\n", utils.B58encode(meta.MessageID[:]))
				log.Printf("Pastebin Address:\t%s\n", utils.B58encode(meta.MessageID[:]))
			}
		}
	} else {
		// Post to server
		server := OptionsVar.Server
		proto := repproto.New(OptionsVar.Socksserver, OptionsVar.Server, GlobalConfigVar.PasteServers...)
		if server == "" {
			server, err = proto.Post(meta.MessageID[:], encMessage)
		} else {
			err = proto.PostSpecific(server, encMessage)
		}
		sep := "/"
		if server != "" && server[len(server)-1] == '/' {
			sep = ""
		}
		if err == nil {
			if meta.MessageKey != nil {
				log.Dataf("STATUS (URL):\t%s/%s_%s\n", server, utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
			}
			if OptionsVar.Embedkey {
				log.Dataf("STATUS (EmbedPublicKey):\t%s_%s\n", utils.B58encode(embedConstantPubKey[:]), utils.B58encode(embedTemporaryPubKey[:]))
				log.Dataf("STATUS (EmbedPrivateKey):\t%s_%s\n", utils.B58encode(embedConstantPrivKey[:]), utils.B58encode(embedTemporaryPrivKey[:]))
			}
			if meta.MessageKey != nil {
				log.Dataf("STATUS (ListInput):\t%s %s %s\n", server, utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
				log.Dataf("STATUS (Message):\t%s_%s\n", utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
				log.Printf("Pastebin Address:\t%s%s%s_%s\n", server, sep, utils.B58encode(meta.MessageID[:]), utils.B58encode(meta.MessageKey[:]))
			} else {
				log.Dataf("STATUS (ListInput):\t%s %s NULL\n", server, utils.B58encode(meta.MessageID[:]))
				log.Dataf("STATUS (MessageID):\t%s\n", utils.B58encode(meta.MessageID[:]))
				log.Printf("Pastebin Address:\t%s%s%s\n", server, sep, utils.B58encode(meta.MessageID[:]))
			}
		}
	}
	if err != nil {
		log.Fatalf("Output failed: %s\n", err)
		log.Sync()
		return 1
	}
	if removeFile != "" {
		// Operation has been successful, remove signer keyfile (if any)
		os.Remove(removeFile)
	}
	return 0
}
Example #15
0
// encrypt message.
func (sender *Sender) encrypt(messageType byte, message []byte, repost bool) (encMessage []byte, meta *MetaDataSend, err error) {
	var Signer *SignKeyPair
	meta = new(MetaDataSend)
	// Set defaults
	if sender.HashCashBits <= 0 {
		sender.HashCashBits = DefaultHashCashBits
	}
	if sender.TotalLength <= 0 {
		sender.TotalLength = DefaultTotalLength
	}
	if sender.PadToLength <= 0 {
		sender.PadToLength = DefaultPadToLength
	}
	// Get signer
	Signer = sender.Signer
	// Verify if (optional) signer produces enough bits, if not, generate a new one
	if Signer != nil {
		ok, _ := hashcash.TestNonce(Signer.PublicKey[:], Signer.Nonce[:], sender.HashCashBits)
		if !ok {
			log.Debugf("Given signer does not produce enough HashCash bits: %x", Signer.PublicKey)
			Signer = nil
		}
	}
	if Signer == nil {
		// We have no signer, so we generate one. Don't make public for sender instance
		log.Info("Generating new HashCash signer...")
		Signer, err = GenKey(sender.HashCashBits)
		if err != nil {
			return nil, nil, err
		}
		log.Info("...new HashCash signer generated")
	}
	// Generate sender keypack. if SenderPrivateKey is set, it will be used
	keypackSender, err := GenSenderKeys(sender.SenderPrivateKey)
	if err != nil {
		return nil, nil, err
	}
	// Generate peer's keypack. If keys are known, they are used
	keypackPeer, err := GenReceiveKeys(sender.ReceiveConstantPublicKey, sender.ReceiveTemporaryPublicKey)
	if err != nil {
		return nil, nil, err
	}
	// We generated new keys, they have to be made available
	if sender.ReceiveConstantPublicKey == nil {
		log.Debug("Using one-time receiver key")
		meta.MessageKey = keypackPeer.ConstantPrivKey // TemporaryPrivKey is deterministic
	}
	// Generate the nonce
	nonce, err := GenNonce()
	if err != nil {
		return nil, nil, err
	}
	myMessage := new(Message)
	// Create our KeyHeader
	myMessage.Header = PackKeyHeader(keypackSender, keypackPeer, nonce)
	// Calculate our shared secret. We are the sender, so last param is true
	sharedSecret := CalcSharedSecret(keypackSender, keypackPeer, nonce, true)
	// Set encryption/padding parameters
	bodyEncryption := EncryptBodyDef{
		IV:           *GenIV(myMessage.Header[:]), // Generate IV from key header, which is uniqueish
		SharedSecret: sharedSecret,
		MessageType:  messageType,
		TotalLength:  sender.TotalLength - SignHeaderSize - KeyHeaderSize,
		PadToLength:  sender.PadToLength,
	}
	log.Debug("Encrypting...")
	body, err := bodyEncryption.EncryptBody(message)
	if err != nil {
		return nil, nil, err
	}
	log.Debug("...encryption done")
	// Convert body to bytes
	myMessage.Body = body.Bytes()
	// Generate the message ID. This has to happen the same way for repost and standard message
	meta.MessageID = *myMessage.CalcMessageID()
	meta.ReceiverConstantPubKey = keypackPeer.ConstantPubKey
	myMessage.SignatureHeader = Signer.Sign(meta.MessageID)

	if repost {
		log.Debug("This is a repost-message!")
		// Cut out padding and set padkey
		meta.PadKey = &body.PadKey
		myMessage.Body = body.BytesNoPadding()
		// Repost messages are not base64 encoded since they are embedded anyways
		return myMessage.Bytes(), meta, nil
	}
	return EncodeBase64(myMessage.Bytes()), meta, nil
}
Example #16
0
// ProcessPost verifies and adds a post to the database.
func (ms MessageServer) ProcessPost(postdata io.ReadCloser, oneTime bool, expireRequest uint64) string {
	data, err := utils.MaxRead(ms.MaxPostSize, postdata)
	if err != nil {
		return "ERROR: Message too big\n"
	}
	if len(data) < ms.MinPostSize {
		return "ERROR: Message too small\n"
	}
	signheader, err := message.Base64Message(data).GetSignHeader()
	if err != nil {
		log.Debugf("Post:GetSignHeader: %s\n", err)
		return "ERROR: Sign Header\n"
	}
	details, err := message.VerifySignature(*signheader, ms.MinHashCashBits)
	if err != nil {
		log.Debugf("Post:VerifySignature: %s\n", err)
		return "ERROR: HashCash\n"
	}
	constantRecipientPub, MessageID, err := deferVerify(data)
	if err != nil {
		log.Debugf("Post:deferVerify: %s\n", err)
		return "ERROR: Verify\n"
	}
	if *MessageID != details.MsgID {
		log.Debugs("Post:MessageID\n")
		return "ERROR: MessageID\n"
	}
	msgStruct := &structs.MessageStruct{
		MessageID:              *MessageID,
		ReceiverConstantPubKey: *constantRecipientPub,
		SignerPub:              details.PublicKey,
		OneTime:                oneTime,
		Sync:                   false,
		Hidden:                 false,
		ExpireRequest:          expireRequest,
	}
	if !oneTime {
		if message.KeyIsSync(constantRecipientPub) {
			msgStruct.Sync = true
		}
	} else {
		msgStruct.Sync = false
	}
	if message.KeyIsHidden(constantRecipientPub) {
		msgStruct.Hidden = true
	}

	sigStruct := &structs.SignerStruct{
		PublicKey: details.PublicKey,
		Nonce:     details.HashCashNonce,
		Bits:      details.HashCashBits,
	}
	sigStruct.MaxMessagesPosted, sigStruct.MaxMessagesRetained, sigStruct.ExpireTarget = ms.calcLimits(details.HashCashBits)
	_, _ = msgStruct, sigStruct
	ms.RandomSleep()
	// err = ms.DB.Put(msgStruct, sigStruct, data)
	err = ms.DB.PutNotify(msgStruct, sigStruct, data, ms.notifyChan)
	ms.RandomSleep()
	if err != nil {
		log.Debugf("Post:MessageDB: %s\n", err)
		return fmt.Sprintf("ERROR: %s\n", err)
	}
	log.Debugf("Post:Added: %x\n", MessageID[:12])
	if ms.Stat {
		stat.Input <- stat.Post
	}
	return "SUCCESS: Connection close\n"
}
Example #17
0
// GetKeyIndex returns the index for a key.
func (ms MessageServer) GetKeyIndex(w http.ResponseWriter, r *http.Request) {
	var pubKey *message.Curve25519Key
	var auth []byte
	start := int64(0)
	count := int64(10)
	w.Header().Set("Content-Type", "text/plain; charset=us-ascii")
	getValues := r.URL.Query()
	if getValues != nil {
		if v, ok := getValues["start"]; ok {
			t, err := strconv.Atoi(v[0])
			if err == nil {
				start = int64(t)
			}
		}
		if v, ok := getValues["count"]; ok {
			t, err := strconv.Atoi(v[0])
			if err == nil {
				count = int64(t)
				if count > ms.MaxIndexKey {
					count = ms.MaxIndexKey
				}
			}
		}
		if v, ok := getValues["key"]; ok {
			if len(v[0]) > message.Curve25519KeySize*10 {
				io.WriteString(w, "ERROR: Bad param\n")
				return
			}
			t := utils.B58decode(v[0])
			if len(t) != message.Curve25519KeySize {
				io.WriteString(w, "ERROR: Bad param\n")
				return
			}
			pubKey = new(message.Curve25519Key)
			copy(pubKey[:], t)
			if v, ok := getValues["auth"]; ok {
				if len(v[0]) > keyauth.AnswerSize*10 {
					io.WriteString(w, "ERROR: Bad param\n")
					return
				}
				auth = utils.B58decode(v[0])
				if len(auth) != keyauth.AnswerSize {
					io.WriteString(w, "ERROR: Bad param\n")
					return
				}
			}
		} else {
			io.WriteString(w, "ERROR: Missing param\n")
			return
		}
	} else {
		io.WriteString(w, "ERROR: Missing param\n")
		return
	}
	if pubKey == nil {
		io.WriteString(w, "ERROR: Missing param\n")
		return
	}
	if message.KeyIsHidden(pubKey) {
		if auth == nil {
			log.Debugs("List:Auth missing\n")
			io.WriteString(w, "ERROR: Authentication required\n")
			return
		}
		answer := [keyauth.AnswerSize]byte{}
		copy(answer[:], auth)
		now := uint64(time.Now().Unix() + ms.TimeSkew)
		if !keyauth.VerifyTime(&answer, now, ms.TimeGrace) {
			log.Debugs("List:Auth timeout\n")
			io.WriteString(w, "ERROR: Authentication failed: Timeout\n")
			return
		}
		privK := [32]byte(*ms.authPrivKey)
		testK := [32]byte(*pubKey)
		if !keyauth.Verify(&answer, &privK, &testK) {
			log.Debugs("List:Auth no verify\n")
			io.WriteString(w, "ERROR: Authentication failed: No Match\n")
			return
		}
	}
	messages, found, err := ms.DB.GetIndex(pubKey, start, count)
	if err != nil && err != fileback.ErrNoMore {
		log.Debugf("List:GetIndex: %s\n", err)
		log.Debugf("List:GetIndex: Key %x\n", pubKey)
		io.WriteString(w, "ERROR: List failed\n")
		return
	}
	io.WriteString(w, "SUCCESS: Data follows\n")
	for _, msg := range messages {
		io.WriteString(w, "IDX: "+strings.Trim(string(msg), " \t\n\r")+"\n")
	}
	if int64(found) < count {
		io.WriteString(w, "CMD: Exceeded\n")
	} else {
		io.WriteString(w, "CMD: Continue\n")
	}
}
Example #18
0
// Run starts the statistics handler.
func Run() {
	start := now()
	postList1 := list.New()
	postList5 := list.New()
	postList60 := list.New()
	postList1440 := list.New()
	fetchList1 := list.New()
	fetchList5 := list.New()
	fetchList60 := list.New()
	fetchList1440 := list.New()
	for {
		m := <-Input
		t := now()
		switch m {
		case Post:
			postList1.PushBack(t)
			postList5.PushBack(t)
			postList60.PushBack(t)
			postList1440.PushBack(t)
		case Fetch:
			fetchList1.PushBack(t)
			fetchList5.PushBack(t)
			fetchList60.PushBack(t)
			fetchList1440.PushBack(t)
		case Show:
			removeOld(postList1, t-oneMin)
			removeOld(postList5, t-fiveMin)
			removeOld(postList60, t-oneHour)
			removeOld(postList1440, t-oneDay)
			removeOld(fetchList1, t-oneMin)
			removeOld(fetchList5, t-fiveMin)
			removeOld(fetchList60, t-oneHour)
			removeOld(fetchList1440, t-oneDay)
			postOneMin := float64(postList1.Len())
			postFiveMin := float64(postList5.Len()) / 5.0
			postOneHour := float64(postList60.Len()) / 60.0
			postOneDay := float64(postList1440.Len()) / 1440.0
			fetchOneMin := float64(fetchList1.Len())
			fetchFiveMin := float64(fetchList5.Len()) / 5.0
			fetchOneHour := float64(fetchList60.Len()) / 60.0
			fetchOneDay := float64(fetchList1440.Len()) / 1440.0
			if t-oneDay >= start {
				log.Debugf("Posts/minute:   %8.3f (1m) %8.3f (5m) %8.3f (1h) %8.3f (24h)\n",
					postOneMin, postFiveMin, postOneHour, postOneDay)
				log.Debugf("Fetches/minute: %8.3f (1m) %8.3f (5m) %8.3f (1h) %8.3f (24h)\n",
					fetchOneMin, fetchFiveMin, fetchOneHour, fetchOneDay)
			} else if t-oneHour >= start {
				log.Debugf("Posts/minute:   %8.3f (1m) %8.3f (5m) %8.3f (1h)\n",
					postOneMin, postFiveMin, postOneHour)
				log.Debugf("Fetches/minute: %8.3f (1m) %8.3f (5m) %8.3f (1h)\n",
					fetchOneMin, fetchFiveMin, fetchOneHour)

			} else if t-fiveMin >= start {
				log.Debugf("Posts/minute:   %8.3f (1m) %8.3f (5m)\n",
					postOneMin, postFiveMin)
				log.Debugf("Fetches/minute: %8.3f (1m) %8.3f (5m)\n",
					fetchOneMin, fetchFiveMin)
			} else {
				log.Debugf("Posts/minute:   %8.3f (1m)\n",
					postOneMin)
				log.Debugf("Fetches/minute: %8.3f (1m)\n",
					fetchOneMin)
			}
		}
	}
}