// VerifySignature verifies a signature header. It checks if the version, signatures and hashcash are correct. func VerifySignature(header [SignHeaderSize]byte, minbits byte) (details *SignatureDetails, err error) { var ok bool if header[0] != byte(Version) { return nil, ErrBadVersion } sd := new(SignatureDetails) copy(sd.MsgID[:], header[signHeaderMsgIDStart:signHeaderMsgIDEnd]) copy(sd.PublicKey[:], header[signHeaderPubkeyStart:signHeaderPubkeyEnd]) copy(sd.HashCashNonce[:], header[signHeaderNonceStart:signHeaderNonceEnd]) signature := new([ed25519.SignatureSize]byte) copy(signature[:], header[signHeaderSignatureStart:signHeaderSignatureEnd]) ok, sd.HashCashBits = hashcash.TestNonce(sd.PublicKey[:], sd.HashCashNonce[:], minbits) if !ok { return sd, ErrHashCash } ok = ed25519.Verify(&sd.PublicKey, sd.MsgID[:], signature) if !ok { return nil, ErrBadSignature } return sd, nil }
// 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 }
func main() { flag.Parse() if *contCalc && *outFile != "" { // Read token d, err := utils.MaxReadFile(2048, *outFile) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } kpt := new(message.SignKeyPair) kp, err := kpt.Unmarshal(d) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } fmt.Print("Continue") start := hashcash.NonceToUInt64(kp.Nonce[:]) _, startBits := hashcash.TestNonce(kp.PublicKey[:], kp.Nonce[:], 0) if len(d) == (ed25519.PublicKeySize + ed25519.PrivateKeySize + hashcash.NonceSize + 1 + 8) { fmt.Print(" from state ") start = hashcash.NonceToUInt64(d[ed25519.PublicKeySize+ed25519.PrivateKeySize+hashcash.NonceSize+1 : ed25519.PublicKeySize+ed25519.PrivateKeySize+hashcash.NonceSize+1+8]) } fmt.Printf(" (%d, bits: %d) ", start, startBits) for { startBits++ nonce, _ := hashcash.ComputeNonceSelect(kp.PublicKey[:], startBits, start, start+hashcash.Steps*8) start = hashcash.NonceToUInt64(nonce[:]) _, nextBits := hashcash.TestNonce(kp.PublicKey[:], nonce, 0) if nextBits > startBits { fmt.Printf("(%d)", nextBits) copy(kp.Nonce[:], nonce) kp.Bits = nextBits startBits = nextBits } fmt.Print(".") newData := append(kp.Marshal(), nonce[:]...) err := utils.OverWriteFile(*outFile, newData) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } if nextBits > byte(*minbits) { fmt.Printf("\n%d reached. Finish.\n", nextBits) os.Exit(0) } } } else if *outDir == "" { keypair, err := message.GenKey(byte(*minbits)) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } b := keypair.Marshal() if *outFile != "" { err := utils.WriteNewFile(*outFile, b) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } } else { os.Stdout.Write(b) os.Stdout.Sync() os.Exit(0) } } else { for { keypair, err := message.GenKey(byte(*minbits)) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } b := keypair.Marshal() err = utils.WriteNewFile(*outDir+string(os.PathSeparator)+strconv.Itoa(int(time.Now().Unix()))+strconv.Itoa(int(time.Now().Nanosecond()))+".hashcash", b) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } } } }