// CmdPost posts a message func CmdPost() int { var inData []byte var err error if OptionsVar.Server == "" { log.Fatal("Server must be specified: --server") return 1 } maxInData := int64(GlobalConfigVar.BodyLength-(message.Curve25519KeySize*2)) * 5 inData, err = inputData(OptionsVar.Infile, maxInData) if err != nil { log.Fatalf("No input data: %s\n", err) return 1 } log.Datas("STATUS (Process):\tPOST\n") proto := repproto.New(OptionsVar.Socksserver, OptionsVar.Server) err = proto.PostSpecific(OptionsVar.Server, inData) if err != nil { log.Fatalf("Output failed: %s\n", err) log.Datas("STATUS (Result):\tFAIL\n") } else { log.Datas("STATUS (Result):\tDONE\n") } log.Sync() return 0 }
func loadStoreMessage(server string, messageID []byte, outfile string) error { proto := repproto.New(OptionsVar.Socksserver, server) log.Dataf("STATUS (Process):\tFETCH\n") inData, err := proto.GetSpecific(server, messageID) if err != nil { log.Dataf("STATUS (Process):\tFAIL\n") log.Fatalf("Fetch error: %s\n", err) return err } err = outputData(outfile, inData) if err != nil { log.Dataf("STATUS (Process):\tFAIL\n") log.Fatalf("Output failed: %s\n", err) return err } return nil }
// CmdPeerList fetches the peerlist and returns a new configfile func CmdPeerList() int { err := getPeers(true) if err != nil { log.Fatalf("Peer discovery failed: %s\n", err) return 1 } return CmdShowConfig() }
// CmdSTM does an STM run to specific server and from specific stmdir func CmdSTM() int { if OptionsVar.Server == "" { log.Fatal("Server must be specified: --server\n") return 1 } if OptionsVar.Stmdir == "" { log.Fatal("Missing parameter: --stmdir\n") return 1 } if !isDir(OptionsVar.Stmdir) { log.Fatalf("stmdir does not exist or is no directory: %s\n", OptionsVar.Stmdir) return 1 } err := listSTM(OptionsVar.Stmdir) // Todo: Test if dir exists if err != nil { log.Errorf("STM Process errors: %s\n", err) return 1 } return 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 }
// CmdDecrypt implements decryption functions func CmdDecrypt() int { var inData, decMessage []byte var err error var meta *message.MetaDataRecieve var privkeystr string var nullKey message.Curve25519Key if OptionsVar.Server == "" { getPeers(false) } if OptionsVar.Stmdir != "" && !isDir(OptionsVar.Stmdir) { log.Fatalf("stmdir does not exist or is no directory: %s\n", OptionsVar.Stmdir) return 1 } // Read input data maxInData := int64(GlobalConfigVar.BodyLength+message.KeyHeaderSize+message.SignHeaderSize) * 4 // Read data from stdin or file if len(flag.Args()) == 0 { inData, err = inputData(OptionsVar.Infile, maxInData) if err != nil { log.Fatalf("No input data: %s\n", err) return 1 } } else { // read data from server (Get). CMDLine is [server/]messageid[_privatekey] var messageidcl []byte var server string server, messageidcl, privkeystr = cmdlineURLparse(flag.Args()...) if server == "" { server = OptionsVar.Server } proto := repproto.New(OptionsVar.Socksserver, OptionsVar.Server, GlobalConfigVar.PasteServers...) if server == "" { server, inData, err = proto.Get(messageidcl) } else { inData, err = proto.GetSpecific(server, messageidcl) } if err != nil { log.Fatalf("Fetch error: %s\n", err) return 1 } log.Dataf("STATUS (FetchServer):\t%s\n", server) } if len(inData) < (message.KeyHeaderSize+message.SignHeaderSize)*4 { log.Fatals("No input data.\n") return 1 } // Set up receiver parameters receiver := message.Receiver{ HashCashBits: GlobalConfigVar.MinHashCash, } if OptionsVar.Senderkey != "" { receiver.SenderPublicKey, _ = utils.ParseKeyPair(OptionsVar.Senderkey) } // Select private key to use if OptionsVar.Keymgt < 0 { if privkeystr == "" { // might have been set from commandline privkeystr = selectPrivKey(OptionsVar.Privkey, GlobalConfigVar.PrivateKey, "tty") } // Parse privkey if privkeystr != "" { receiver.ReceiveConstantPrivateKey, receiver.ReceiveTemporaryPrivateKey = utils.ParseKeyPair(privkeystr) } } else { // Register callback, OptionsVar.keymgt == fd keyMgtFile, callback := KeyCallBack(OptionsVar.Keymgt) defer keyMgtFile.Close() receiver.KeyCallBack = callback } log.Datas("STATUS (Process):\tREAD\n") // Decrypt decMessage, meta, err = receiver.Decrypt(inData) if err != nil { log.Fatalf("%s\n", err) return 1 } log.Dataf("STATUS (MessageID):\t%s\n", utils.B58encode(meta.MessageID[:])) log.Dataf("STATUS (RecPubKey):\t%s\n", utils.B58encode(meta.ReceiveConstantPublicKey[:])) log.Dataf("STATUS (SenderPubKey):\t%s\n", utils.B58encode(meta.SenderConstantPublicKey[:])) // Get replyKeys embedConstant, embedTemporary := utils.DecodeEmbedded(decMessage[:message.Curve25519KeySize*2]) if *embedConstant != nullKey { log.Dataf("STATUS (EmbedPublicKey):\t%s_%s\n", utils.B58encode(embedConstant[:]), utils.B58encode(embedTemporary[:])) } // If messageType list: print list to DATA if meta.MessageType == message.MsgTypeList { log.Datas("STATUS (Process):\tLIST\n") err := utils.VerifyListContent(decMessage[message.Curve25519KeySize*2:]) if err != nil { log.Fatalf("%s\n", err) return 1 } lines := bytes.Split(decMessage[message.Curve25519KeySize*2:], []byte("\n")) for _, l := range lines { log.Dataf("STATUS (ListItem):\t%s\n", string(l)) } return 0 } decMessage = decMessage[message.Curve25519KeySize*2:] // meta.MessageType if meta.MessageType == message.MsgTypeRepost { log.Datas("STATUS (Process):\tREPOST\n") // If messageType repost: get padkey,mindelay,maxdelay. Repad padkey, minDelay, maxDelay := utils.DecodeRepostHeader(decMessage[:utils.RepostHeaderSize]) timePoint := utils.STM(int(minDelay), int(maxDelay)) log.Dataf("STATUS (STM):\t%d %d %d\n", minDelay, maxDelay, timePoint) repostMsgt := message.RePad(decMessage[utils.RepostHeaderSize:], padkey, GlobalConfigVar.BodyLength) signHeader := new([message.SignHeaderSize]byte) copy(signHeader[:], repostMsgt[:message.SignHeaderSize]) details, err := message.VerifySignature(*signHeader, GlobalConfigVar.MinHashCash) if err != nil { log.Fatalf("%s\n", err) return 1 } msgIDMsg := message.CalcMessageID(repostMsgt) if *msgIDMsg != details.MsgID { log.Fatals("MessageID conflict\n") return 1 } log.Dataf("STATUS (MessageIDSig):\t%s\n", utils.B58encode(details.MsgID[:])) log.Dataf("STATUS (PubKeySig):\t%s\n", utils.B58encode(details.PublicKey[:])) log.Dataf("STATUS (NonceSig):\t%x\n", details.HashCashNonce[:]) log.Dataf("STATUS (BitsSig):\t%d\n", details.HashCashBits) decMessage = message.EncodeBase64(repostMsgt) if OptionsVar.Stmdir != "" { // Exist/Dir test done early filename := fmt.Sprintf("%s%s%d.%s", OptionsVar.Stmdir, string(os.PathSeparator), timePoint, utils.B58encode(msgIDMsg[:])) log.Dataf("STATUS (STMFile):\t%s\n", filename) err := utils.WriteNewFile(filename, decMessage) if err != nil { log.Fatalf("%s\n", err) return 1 } return 0 } } err = outputData(OptionsVar.Outfile, decMessage) if err != nil { log.Fatalf("Output failed: %s\n", err) return 1 } return 0 }
// CmdIndex returns the index for a private key func CmdIndex() int { var server string var err error var pubkey *message.Curve25519Key var privkey message.Curve25519Key var messages []*structs.MessageStruct var moreMessages bool if OptionsVar.Server == "" { getPeers(false) } if OptionsVar.Outdir != "" && !isDir(OptionsVar.Outdir) { log.Fatalf("outdir does not exist or is no directory: %s", OptionsVar.Outdir) return 1 } // privkey must be set privkeystr := selectPrivKey(OptionsVar.Privkey, GlobalConfigVar.PrivateKey, "tty") if privkeystr == "" { log.Fatal("Private key missing: --privkey\n") return 1 } privT := utils.B58decode(privkeystr) copy(privkey[:], privT) pubkey = message.CalcPub(&privkey) if OptionsVar.Server != "" { server = OptionsVar.Server } proto := repproto.New(OptionsVar.Socksserver, OptionsVar.Server) log.Dataf("STATUS (Process):\tLIST\n") if server != "" { fmt.Println("Specific server") messages, moreMessages, err = proto.ListSpecific(server, pubkey[:], privkey[:], OptionsVar.Start, OptionsVar.Count) } else { fmt.Println("Any server") server, messages, moreMessages, err = proto.List(pubkey[:], privkey[:], OptionsVar.Start, OptionsVar.Count) } if err != nil { log.Fatalf("List error: %s\n", err) return 1 } if len(messages) > 0 { fmt.Print("Index\t\tMessageID\n") fmt.Print("------------------------------------------------------------\n") } for _, msg := range messages { log.Dataf("STATUS (MessageList):\t%d %s %s %d %d\n", msg.Counter, utils.B58encode(msg.MessageID[:]), utils.B58encode(msg.SignerPub[:]), msg.PostTime, msg.ExpireTime) fmt.Printf("%d\t\t%s\n", msg.Counter, utils.B58encode(msg.MessageID[:])) } log.Dataf("STATUS (ListResult):\t%d %d %t\n", OptionsVar.Start, OptionsVar.Count, moreMessages) if len(messages) > 0 { fmt.Print("------------------------------------------------------------\n") } if moreMessages { fmt.Print("More messages may be available\n") } else { fmt.Print("Listing complete\n") } if OptionsVar.Outdir != "" { log.Dataf("STATUS (Process):\tFETCHMANY\n") fmt.Print("Fetching messages...") hasErrors := 0 for _, msg := range messages { log.Dataf("STATUS (Fetch):\t%s\n", utils.B58encode(msg.MessageID[:])) err = loadStoreMessage(server, msg.MessageID[:], OptionsVar.Outdir+string(os.PathSeparator)+utils.B58encode(msg.MessageID[:])) // use index server for download, store with name messageID if err != nil { fmt.Print(".F") hasErrors++ log.Dataf("STATUS (FetchError):\t%s\n", utils.B58encode(msg.MessageID[:])) } else { fmt.Print(".o") log.Dataf("STATUS (FetchComplete):\t%s\n", utils.B58encode(msg.MessageID[:])) } } if hasErrors > 0 { fmt.Print(". Some errors during download.\n") log.Dataf("STATUS (FetchResult):\tERROS %d\n", hasErrors) } else { fmt.Print(". Download complete.\n") log.Dataf("STATUS (FetchResult):\tOK\n") } } log.Sync() // server can be set return 0 }
// CmdIndex returns the index for a private key func CmdIndex() int { var server string var err error var pubkey *message.Curve25519Key var privkey message.Curve25519Key var messages []*structs.MessageStruct var moreMessages bool if OptionsVar.Server == "" { // getPeers(false). Meaningless for index calls log.Fatal("--index requires --server to be specified.\n") return 1 } server = OptionsVar.Server if OptionsVar.Outdir != "" && !isDir(OptionsVar.Outdir) { log.Fatalf("outdir does not exist or is no directory: %s", OptionsVar.Outdir) return 1 } // privkey must be set privkeystr := selectPrivKey(OptionsVar.Privkey, GlobalConfigVar.PrivateKey, "tty") if privkeystr == "" { log.Fatal("Private key missing: --privkey\n") return 1 } // Test if long key is given, if yes, use only first part if pos := strings.Index(privkeystr, "_"); pos > 0 { privkeystr = privkeystr[:pos] } privT := utils.B58decode(privkeystr) copy(privkey[:], privT) pubkey = message.CalcPub(&privkey) proto := repproto.New(OptionsVar.Socksserver, OptionsVar.Server) // If we want to change to using the server list instead. Not a great idea // proto := repproto.New(OptionsVar.Socksserver, OptionsVar.Server, GlobalConfigVar.PasteServers...) // re-enable if we want to use the server list: server, messages, moreMessages, err = proto.List(pubkey[:], privkey[:], OptionsVar.Start, OptionsVar.Count) log.Dataf("STATUS (Process):\tLIST\n") messages, moreMessages, err = proto.ListSpecific(server, pubkey[:], privkey[:], OptionsVar.Start, OptionsVar.Count) if err != nil { log.Fatalf("List error: %s\n", err) return 1 } if len(messages) > 0 { fmt.Print("Index\t\tMessageID\n") fmt.Print("------------------------------------------------------------\n") } for _, msg := range messages { log.Dataf("STATUS (MessageList):\t%d %s %s %d %d\n", msg.Counter, utils.B58encode(msg.MessageID[:]), utils.B58encode(msg.SignerPub[:]), msg.PostTime, msg.ExpireTime) fmt.Printf("%d\t\t%s\n", msg.Counter, utils.B58encode(msg.MessageID[:])) } log.Dataf("STATUS (ListResult):\t%d %d %t\n", OptionsVar.Start, OptionsVar.Count, moreMessages) if len(messages) > 0 { fmt.Print("------------------------------------------------------------\n") } if moreMessages { fmt.Print("More messages may be available\n") } else { fmt.Print("Listing complete\n") } if OptionsVar.Outdir != "" { log.Dataf("STATUS (Process):\tFETCHMANY\n") fmt.Print("Fetching messages...") hasErrors := 0 for _, msg := range messages { log.Dataf("STATUS (Fetch):\t%s\n", utils.B58encode(msg.MessageID[:])) err = loadStoreMessage(server, msg.MessageID[:], OptionsVar.Outdir+string(os.PathSeparator)+utils.B58encode(msg.MessageID[:])) // use index server for download, store with name messageID if err != nil { fmt.Print(".F") hasErrors++ log.Dataf("STATUS (FetchError):\t%s\n", utils.B58encode(msg.MessageID[:])) } else { fmt.Print(".o") log.Dataf("STATUS (FetchComplete):\t%s\n", utils.B58encode(msg.MessageID[:])) } } if hasErrors > 0 { fmt.Print(". Some errors during download.\n") log.Dataf("STATUS (FetchResult):\tERROS %d\n", hasErrors) } else { fmt.Print(". Download complete.\n") log.Dataf("STATUS (FetchResult):\tOK\n") } } log.Sync() // server can be set return 0 }