diff --git a/nip44.go b/nip44.go index bc3dd43..fb877ab 100644 --- a/nip44.go +++ b/nip44.go @@ -8,6 +8,7 @@ import ( "encoding/base64" "encoding/binary" "errors" + "fmt" "io" "math" @@ -50,7 +51,7 @@ func Encrypt(conversationKey []byte, plaintext string, options *EncryptOptions) } } if version != 2 { - return "", errors.New("unknown version") + return "", errors.New(fmt.Sprintf("unknown version %d", version)) } if len(salt) != 32 { return "", errors.New("salt must be 32 bytes") @@ -76,6 +77,7 @@ func Decrypt(conversationKey []byte, ciphertext string) (string, error) { var ( version int = 2 decoded []byte + cLen int dLen int salt []byte ciphertext_ []byte @@ -88,6 +90,10 @@ func Decrypt(conversationKey []byte, ciphertext string) (string, error) { unpadded []byte err error ) + cLen = len(ciphertext) + if cLen < 132 || cLen > 87472 { + return "", errors.New(fmt.Sprintf("invalid payload length: %d", cLen)) + } if ciphertext[0:1] == "#" { return "", errors.New("unknown version") } @@ -95,9 +101,12 @@ func Decrypt(conversationKey []byte, ciphertext string) (string, error) { return "", errors.New("invalid base64") } if version = int(decoded[0]); version != 2 { - return "", errors.New("unknown version") + return "", errors.New(fmt.Sprintf("unknown version %d", version)) } dLen = len(decoded) + if dLen < 99 || dLen > 65603 { + return "", errors.New(fmt.Sprintf("invalid data length: %d", dLen)) + } salt, ciphertext_, hmac_ = decoded[1:33], decoded[33:dLen-32], decoded[dLen-32:] if enc, nonce, auth, err = messageKeys(conversationKey, salt); err != nil { return "", err @@ -109,6 +118,10 @@ func Decrypt(conversationKey []byte, ciphertext string) (string, error) { return "", err } unpaddedLen = binary.BigEndian.Uint16(padded[0:2]) + if unpaddedLen < uint16(MinPlaintextSize) || unpaddedLen > uint16(MaxPlaintextSize) || + len(unpadded) == 0 || len(unpadded) != int(unpaddedLen) || len(padded) != 2+calcPadding(int(unpaddedLen)) { + return "", errors.New("invalid padding") + } unpadded = padded[2 : unpaddedLen+2] if len(unpadded) == 0 || len(unpadded) != int(unpaddedLen) || len(padded) != 2+calcPadding(int(unpaddedLen)) { return "", errors.New("invalid padding") diff --git a/nip44_test.go b/nip44_test.go index 80c689e..f9fc1a0 100644 --- a/nip44_test.go +++ b/nip44_test.go @@ -79,7 +79,7 @@ func assertCryptPub(t *testing.T, sk1 string, pub2 string, conversationKey strin assert.Equal(t, decrypted, plaintext, "wrong decryption") } -func assertDecryptFail(t *testing.T, sk1 string, pub2 string, conversationKey string, ciphertext string, msg string) { +func assertDecryptFail(t *testing.T, conversationKey string, plaintext string, ciphertext string, msg string) { var ( k1 []byte ok bool @@ -89,9 +89,6 @@ func assertDecryptFail(t *testing.T, sk1 string, pub2 string, conversationKey st if ok = assert.NoErrorf(t, err, "hex decode failed for conversation key: %v", err); !ok { return } - if ok = assertConversationKeyGenerationPub(t, sk1, pub2, conversationKey); !ok { - return - } _, err = nip44.Decrypt(k1, ciphertext) assert.ErrorContains(t, err, msg) } @@ -507,87 +504,126 @@ func TestConversationKeyFail008(t *testing.T) { ) } -func TestCryptFail001(t *testing.T) { +func TestDecryptFail001(t *testing.T) { assertDecryptFail(t, - "2573d1e9b9ac5de5d570f652cbb9e8d4f235e3d3d334181448e87c417f374e83", - "8348c2d35549098706e5bab7966d9a9c72fbf6554e918f41c2b6cb275f79ec13", - "8673ec68393a997bfad7eab8661461daf8b3931b7e885d78312a3fb7fe17f41a", - "##Atqupco0WyaOW2IGDKcshwxI9xO8HgD/P8Ddt46CbxDbOsrsqIEybscEwg5rnI/Cx03mDSmeweOLKD7dw5BDZQDxXSlCwX1LIcTJEZaJPTz98Ftu0zSE0d93ED7OtdlvNeZx", + "ca2527a037347b91bea0c8a30fc8d9600ffd81ec00038671e3a0f0cb0fc9f642", + // "daaea5ca345b268e5b62060ca72c870c48f713bc1e00ff3fc0ddb78e826f10db", + "n o b l e", + "#Atqupco0WyaOW2IGDKcshwxI9xO8HgD/P8Ddt46CbxDbrhdG8VmJdU0MIDf06CUvEvdnr1cp1fiMtlM/GrE92xAc1K5odTpCzUB+mjXgbaqtntBUbTToSUoT0ovrlPwzGjyp", "unknown version", ) } -func TestCryptFail002(t *testing.T) { +func TestDecryptFail002(t *testing.T) { assertDecryptFail(t, - "11063318c5cb3cd9cafcced42b4db5ea02ec976ed995962d2bc1fa1e9b52e29f", - "5c49873b6eac3dd363325250cc55d5dd4c7ce9a885134580405736d83506bb74", - "e2aad10de00913088e5cb0f73fa526a6a17e95763cc5b2a127022f5ea5a73445", - "AK1AjUvoYW3IS7C/BGRUoqEC7ayTfDUgnEPNeWTF/reBA4fZmoHrtrz5I5pCHuwWZ22qqL/Xt1VidEZGMLds0yaJ5VwUbeEifEJlPICOFt1ssZJxCUf43HvRwCVTFskbhSMh", - "unknown version", + "36f04e558af246352dcf73b692fbd3646a2207bd8abd4b1cd26b234db84d9481", + // "ad408d4be8616dc84bb0bf046454a2a102edac937c35209c43cd7964c5feb781", + "⚠️", + "AK1AjUvoYW3IS7C/BGRUoqEC7ayTfDUgnEPNeWTF/reBZFaha6EAIRueE9D1B1RuoiuFScC0Q94yjIuxZD3JStQtE8JMNacWFs9rlYP+ZydtHhRucp+lxfdvFlaGV/sQlqZz", + "unknown version 0", ) } -func TestCryptFail003(t *testing.T) { +func TestDecryptFail003(t *testing.T) { assertDecryptFail(t, - "2573d1e9b9ac5de5d570f652cbb9e8d4f235e3d3d334181448e87c417f374e83", - "8348c2d35549098706e5bab7966d9a9c72fbf6554e918f41c2b6cb275f79ec13", - "8673ec68393a997bfad7eab8661461daf8b3931b7e885d78312a3fb7fe17f41a", - "Atqupco0WyaOW2IGDKcshwxI9xO8HgD/P8Ddt46CbxDbOsrsqIEybscEwg5rnI/Cx03mDSmeweOLKD,7dw5BDZQDxXSlCwX1LIcTJEZaJPTz98Ftu0zSE0d93ED7OtdlvNeZx", + "ca2527a037347b91bea0c8a30fc8d9600ffd81ec00038671e3a0f0cb0fc9f642", + // "daaea5ca345b268e5b62060ca72c870c48f713bc1e00ff3fc0ddb78e826f10db", + "n o s t r", + "Atфupco0WyaOW2IGDKcshwxI9xO8HgD/P8Ddt46CbxDbrhdG8VmJZE0UICD06CUvEvdnr1cp1fiMtlM/GrE92xAc1EwsVCQEgWEu2gsHUVf4JAa3TpgkmFc3TWsax0v6n/Wq", "invalid base64", ) } -func TestCryptFail004(t *testing.T) { +func TestDecryptFail004(t *testing.T) { assertDecryptFail(t, - "5a2f39347fed3883c9fe05868a8f6156a292c45f606bc610495fcc020ed158f7", - "775bbfeba58d07f9d1fbb862e306ac780f39e5418043dadb547c7b5900245e71", - "2e70c0a1cde884b88392458ca86148d859b273a5695ede5bbe41f731d7d88ffd", - "Agn/l3ULCEAS4V7LhGFM6IGA17jsDUaFCKhrbXDANholdUejFZPARM22IvOqp1U/UmFSkeSyTBYbbwy5ykmi+mKiEcWL+nVmTOf28MMiC+rTpZys/8p1hqQFpn+XWZRPrVay", + "cff7bd6a3e29a450fd27f6c125d5edeb0987c475fd1e8d97591e0d4d8a89763c", + // "09ff97750b084012e15ecb84614ce88180d7b8ec0d468508a86b6d70c0361a25", + "¯\\_(ツ)_/¯", + "Agn/l3ULCEAS4V7LhGFM6IGA17jsDUaFCKhrbXDANholyySBfeh+EN8wNB9gaLlg4j6wdBYh+3oK+mnxWu3NKRbSvQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "invalid hmac", ) } -func TestCryptFail005(t *testing.T) { +func TestDecryptFail005(t *testing.T) { assertDecryptFail(t, - "067eda13c4a36090ad28a7a183e9df611186ca01f63cb30fcdfa615ebfd6fb6d", - "32c1ece2c5dd2160ad03b243f50eff12db605b86ac92da47eacc78144bf0cdd3", - "a808915e31afc5b853d654d2519632dac7298ee2ecddc11695b8eba925935c2a", - "AmWxSwuUmqp9UsQX63U7OQ6K1thLI69L7G2b+j4DoIr0U0P/M1/oKm95z8qz6Kg0zQawLzwk3DskvWA2drXP4zK+tzHpKvWq0KOdx5MdypboSQsP4NXfhh2KoUffjkyIOiMA", + "cfcc9cf682dfb00b11357f65bdc45e29156b69db424d20b3596919074f5bf957", + // "65b14b0b949aaa7d52c417eb753b390e8ad6d84b23af4bec6d9bfa3e03a08af4", + "🥎", + "AmWxSwuUmqp9UsQX63U7OQ6K1thLI69L7G2b+j4DoIr0oRWQ8avl4OLqWZiTJ10vIgKrNqjoaX+fNhE9RqmR5g0f6BtUg1ijFMz71MO1D4lQLQfW7+UHva8PGYgQ1QpHlKgR", "invalid hmac", ) } -func TestCryptFail006(t *testing.T) { +func TestDecryptFail006(t *testing.T) { assertDecryptFail(t, - "3e7be560fb9f8c965c48953dbd00411d48577e200cf00d7cc427e49d0e8d9c01", - "e539e5fee58a337307e2a937ee9a7561b45876fb5df405c5e7be3ee564b239cc", - "6ee3efc4255e3b8270e5dd3f7dc7f6b60878cda6218c8df34a3261cd48744931", - "Anq2XbuLvCuONcr7V0UxTh8FAyWoZNEdBHXvdbNmDZHBu7F9m36yBd58mVUBB5ktBTOJREDaQT1KAyPmZidP+IRea1lNw5YAEK7+pbnpfCw8CD0i2n8Pf2IDWlKDhLiVvatw", + "5254827d29177622d40a7b67cad014fe7137700c3c523903ebbe3e1b74d40214", + // "7ab65dbb8bbc2b8e35cafb5745314e1f050325a864d11d0475ef75b3660d91c1", + "elliptic-curve cryptography", + "Anq2XbuLvCuONcr7V0UxTh8FAyWoZNEdBHXvdbNmDZHB573MI7R7rrTYftpqmvUpahmBC2sngmI14/L0HjOZ7lWGJlzdh6luiOnGPc46cGxf08MRC4CIuxx3i2Lm0KqgJ7vA", "invalid padding", ) } -func TestCryptFail007(t *testing.T) { +func TestDecryptFail007(t *testing.T) { assertDecryptFail(t, - "c22e1d4de967aa39dc143354d8f596cec1d7c912c3140831fff2976ce3e387c1", - "4e405be192677a2da95ffc733950777213bf880cf7c3b084eeb6f3fe5bd43705", - "1675a773dbf6fbcbef6a293004a4504b6c856978be738b10584b0269d437c8d1", - "An1Cg+O1TIhdav7ogfSOYvCj9dep4ctxzKtZSniCw5MwhT0hvSnF9Xjp9Lml792qtNbmAVvR6laukTe9eYEjeWPpZFxtkVpYTbbL9wDKFeplDMKsUKVa+roSeSvv0ela9seDVl2Sfso=", + "fea39aca9aa8340c3a78ae1f0902aa7e726946e4efcd7783379df8096029c496", + // "7d4283e3b54c885d6afee881f48e62f0a3f5d7a9e1cb71ccab594a7882c39330", + "noble", + "An1Cg+O1TIhdav7ogfSOYvCj9dep4ctxzKtZSniCw5MwRrrPJFyAQYZh5VpjC2QYzny5LIQ9v9lhqmZR4WBYRNJ0ognHVNMwiFV1SHpvUFT8HHZN/m/QarflbvDHAtO6pY16", "invalid padding", ) } -func TestCryptFail008(t *testing.T) { +func TestDecryptFail008(t *testing.T) { assertDecryptFail(t, - "be1edab14c5912e5c59084f197f0945242e969c363096cccb59af8898815096f", - "9eaf0775d971e4941c97189232542e1daefcdb7dddafc39bcea2520217710ba2", - "1741a44c052d5ae363c7845441f73d2b6c28d9bfb3006190012bba12eb4c774b", - "Am+f1yZnwnOs0jymZTcRpwhDRHTdnrFcPtsBzpqVdD6bL9HUMo3Mjkz4bjQo/FJF2LWHmaCr9Byc3hU9D7we+EkNBWenBHasT1G52fZk9r3NKeOC1hLezNwBLr7XXiULh+NbMBDtJh9/aQh1uZ9EpAfeISOzbZXwYwf0P5M85g9XER8hZ2fgJDLb4qMOuQRG6CrPezhr357nS3UHwPC2qHo3uKACxhE+2td+965yDcvMTx4KYTQg1zNhd7PA5v/WPnWeq2B623yLxlevUuo/OvXplFho3QVy7s5QZVop6qV2g2/l/SIsvD0HIcv3V35sywOCBR0K4VHgduFqkx/LEF3NGgAbjONXQHX8ZKushsEeR4TxlFoRSovAyYjhWolz+Ok3KJL2Ertds3H+M/Bdl2WnZGT0IbjZjn3DS+b1Ke0R0X4Onww2ZG3+7o6ncIwTc+lh1O7YQn00V0HJ+EIp03heKV2zWdVSC615By/+Yt9KAiV56n5+02GAuNqA", + "0c4cffb7a6f7e706ec94b2e879f1fc54ff8de38d8db87e11787694d5392d5b3f", + // "6f9fd72667c273acd23ca6653711a708434474dd9eb15c3edb01ce9a95743e9b", + "censorship-resistant and global social network", + "Am+f1yZnwnOs0jymZTcRpwhDRHTdnrFcPtsBzpqVdD6b2NZDaNm/TPkZGr75kbB6tCSoq7YRcbPiNfJXNch3Tf+o9+zZTMxwjgX/nm3yDKR2kHQMBhVleCB9uPuljl40AJ8kXRD0gjw+aYRJFUMK9gCETZAjjmrsCM+nGRZ1FfNsHr6Z", "invalid padding", ) } +func TestDecryptFail009(t *testing.T) { + assertDecryptFail(t, + "5cd2d13b9e355aeb2452afbd3786870dbeecb9d355b12cb0a3b6e9da5744cd35", + // "b60036976a1ada277b948fd4caa065304b96964742b89d26f26a25263a5060bd", + "0", + "", + "invalid payload length: 0", + ) +} + +func TestDecryptFail010(t *testing.T) { + assertDecryptFail(t, + "d61d3f09c7dfe1c0be91af7109b60a7d9d498920c90cbba1e137320fdd938853", + // "1a29d02c8b4527745a2ccb38bfa45655deb37bc338ab9289d756354cea1fd07c", + "1", + "Ag==", + "invalid payload length: 4", + ) +} + +func TestDecryptFail011(t *testing.T) { + assertDecryptFail(t, + "873bb0fc665eb950a8e7d5971965539f6ebd645c83c08cd6a85aafbad0f0bc47", + // "c826d3c38e765ab8cc42060116cd1464b2a6ce01d33deba5dedfb48615306d4a", + "2", + "AqxgToSh3H7iLYRJjoWAM+vSv/Y1mgNlm6OWWjOYUClrFF8=", + "invalid payload length: 48", + ) +} +func TestDecryptFail012(t *testing.T) { + assertDecryptFail(t, + "9f2fef8f5401ac33f74641b568a7a30bb19409c76ffdc5eae2db6b39d2617fbe", + // "9ff6484642545221624eaac7b9ea27133a4cc2356682a6033aceeef043549861", + "3", + "Ap/2SEZCVFIhYk6qx7nqJxM6TMI1ZoKmAzrO7vBDVJhhuZXWiM20i/tIsbjT0KxkJs2MZjh1oXNYMO9ggfk7i47WQA==", + "invalid payload length: 92", + ) +} + func TestConversationKey001(t *testing.T) { assertConversationKeyGenerationPub(t, "315e59ff51cb9209768cf7da80791ddcaae56ac9775eb25b6dee1234bc5d2268",