// it's likely a signature. sc.Type = CryptoMessageTypeAttachedSignature default: return false } sc.Format = CryptoMessageFormatPGP return true } func matchesSaltpackType(messageStart string, typeString string) bool { exp := "^\\s*BEGIN ([a-zA-Z0-9]+ )?SALTPACK " + typeString + "." match, err := regexp.MatchString(exp, messageStart) return match && (err == nil) } var encryptionArmorHeader = saltpack.MakeArmorHeader(saltpack.MessageTypeEncryption, KeybaseSaltpackBrand) var signedArmorHeader = saltpack.MakeArmorHeader(saltpack.MessageTypeAttachedSignature, KeybaseSaltpackBrand) var detachedArmorHeader = saltpack.MakeArmorHeader(saltpack.MessageTypeDetachedSignature, KeybaseSaltpackBrand) // ClassifyStream takes a stream reader in, and returns a likely classification // of that stream without consuming any data from it. It returns a reader that you // should read from instead, in addition to the classification. If classification // fails, there will be a `UnknownStreamError`, or additional EOF errors if the // stream ended beform classification could go. func ClassifyStream(r io.Reader) (sc StreamClassification, out io.Reader, err error) { peeker := NewStreamPeeker(r) var buf [100]byte var n int if n, err = peeker.Peek(buf[:]); err != nil { // ErrUnexpectedEOF might just mean we read less than 100 bytes if err == io.ErrUnexpectedEOF && len(buf) > 0 {
// Encrypt a message, and make sure recipients can decode it, and // non-recipients can't decode it. func TestSaltpackEncDec(t *testing.T) { senderKP, err := GenerateNaclDHKeyPair() if err != nil { t.Fatal(err) } var receiverKPs []NaclDHKeyPair var receiverPKs []NaclDHKeyPublic for i := 0; i < 12; i++ { kp, err := GenerateNaclDHKeyPair() if err != nil { t.Fatal(err) } receiverKPs = append(receiverKPs, kp) receiverPKs = append(receiverPKs, kp.Public) } nonReceiverKP, err := GenerateNaclDHKeyPair() if err != nil { t.Fatal(err) } message := "The Magic Words are Squeamish Ossifrage" var buf outputBuffer arg := SaltpackEncryptArg{ Source: strings.NewReader(message), Sink: &buf, Receivers: receiverPKs, Sender: senderKP, } if err := SaltpackEncrypt(G, &arg); err != nil { t.Fatal(err) } ciphertext := buf.String() if !strings.HasPrefix(ciphertext, saltpack.MakeArmorHeader(saltpack.MessageTypeEncryption, KeybaseSaltpackBrand)) { t.Errorf("ciphertext doesn't have header: %s", ciphertext) } if !strings.HasSuffix(ciphertext, saltpack.MakeArmorFooter(saltpack.MessageTypeEncryption, KeybaseSaltpackBrand)+".\n") { t.Errorf("ciphertext doesn't have footer: %s", ciphertext) } for _, key := range receiverKPs { buf.Reset() _, err = SaltpackDecrypt(G, strings.NewReader(ciphertext), &buf, key, nil) if err != nil { t.Fatal(err) } plaintext := buf.String() if plaintext != message { t.Errorf("expected %s, got %s", message, plaintext) } } // Sender is a non-recipient, too. nonReceiverKPs := []NaclDHKeyPair{nonReceiverKP, senderKP} for _, kp := range nonReceiverKPs { buf.Reset() _, err = SaltpackDecrypt(G, strings.NewReader(ciphertext), &buf, kp, nil) if err != saltpack.ErrNoDecryptionKey { t.Fatal(err) } } }