示例#1
0
// 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
}
示例#2
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
}
示例#3
0
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)
			}
		}
	}
}