1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-23 22:46:44 +01:00

EncryptedRecipientData TLV stream should not be length-prefixed (#2029)

* TLV streams contain size of fields already

* Update test vectors
This commit is contained in:
thomash-acinq 2021-10-25 11:52:43 +02:00 committed by GitHub
parent 765a0c5436
commit 1573f7be05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 30 deletions

View file

@ -62,7 +62,7 @@ object EncryptedRecipientDataCodecs {
.typecase(UInt64(4), outgoingNodeId)
.typecase(UInt64(6), recipientSecret)
val encryptedRecipientDataCodec: Codec[TlvStream[EncryptedRecipientDataTlv]] = TlvCodecs.lengthPrefixedTlvStream[EncryptedRecipientDataTlv](encryptedRecipientDataTlvCodec).complete
val encryptedRecipientDataCodec: Codec[TlvStream[EncryptedRecipientDataTlv]] = TlvCodecs.tlvStream[EncryptedRecipientDataTlv](encryptedRecipientDataTlvCodec).complete
/**
* Decrypt and decode the contents of an encrypted_recipient_data TLV field.

View file

@ -370,7 +370,7 @@ class SphinxSpec extends AnyFunSuite {
assert(blindedRoute.introductionNode.publicKey === publicKeys(0))
assert(blindedRoute.introductionNode.blindedPublicKey === PublicKey(hex"02ec68ed555f5d18b12fe0e2208563c3566032967cf11dc29b20c345449f9a50a2"))
assert(blindedRoute.introductionNode.blindingEphemeralKey === PublicKey(hex"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f"))
assert(blindedRoute.introductionNode.encryptedPayload === hex"a245b767bd52520bdf8179b2dc681d1a36c2ededaf59429dfc4bea342fa460c9")
assert(blindedRoute.introductionNode.encryptedPayload === hex"af4fbf67bd52520bdfab6a88cd4e7f22ffad08d8b153b17ff303f93fdb4712")
assert(blindedRoute.nodeIds === Seq(
publicKeys(0),
PublicKey(hex"022b09d77fb3374ee3ed9d2153e15e9962944ad1690327cbb0a9acb7d90f168763"),
@ -386,10 +386,10 @@ class SphinxSpec extends AnyFunSuite {
))
assert(blindedRoute.encryptedPayloads === blindedRoute.introductionNode.encryptedPayload +: blindedRoute.blindedNodes.map(_.encryptedPayload))
assert(blindedRoute.blindedNodes.map(_.encryptedPayload) === Seq(
hex"38748f94ead7de2a54fc43e8bb927bfc377dda7ed5a2e36b327b739c3c82a602e43e07e378f17cd46ee32d987eb8b6d03b3403acb095bd2868f640b92ea1",
hex"a5ddddd448f15208452f4d65da0d53679e9652c8f9c9882d795388a492b4060afb5f2f556e36aed51d089f60f7c94f714b34cb30f1dac0c17f3855a827cb",
hex"7ead52884542d180e76fec6ae2d137b6b4c771dc0d41390e992839dea0f4fcefb4a31589125e2ba535d0dc3bf1bc94e6c9039323579547921686d3b54c22",
hex"4642ce64cbf146ffd73299501d65c56052af4acd681d9d0882728c6f399ace90392b694d5e347612dc1417f1b31e5f5dfdfb4ca5e8a24a681898ec5784f7",
hex"146c9694ead7de2a54fc43e8bb927bfc377dda7ed5a2e36b327b739e368aa602e43e07e14b3d7ed493e7ea6245924d9a03d22f0fca56babd7da19f49b7",
hex"8ad7d5d448f15208417a1840f82274101b3c254c24b1b49fd676fd0c4293c9aa66ed51da52579e934a869f016f213044d1b13b63bf586e9c9832106b59",
hex"52a45a884542d180e76fe84fc13e71a01f65d943ff89aed29b94644a91b037b9143cfda8f1ff25ba61c37108a5ae57d9ddc5ab688ee8b2f9f6bd94522c",
hex"6a4ac764cbf146ffd73299563b07c56052af4acd681d9d0882728c6f399ace90392b694d5e347612dc1417f1b3a9c82d6d4db18b6eb32134e554db7d00",
))
// The introduction point can decrypt its encrypted payload and obtain the next ephemeral public key.
@ -442,9 +442,9 @@ class SphinxSpec extends AnyFunSuite {
// The sender obtains this information (e.g. from a Bolt11 invoice) and prepends two normal hops to reach the introduction node.
val nodeIds = publicKeys.take(2) ++ blindedRoute.nodeIds
assert(blindedRoute.encryptedPayloads === Seq(
hex"192256e1c0b289eee9a509bf94455c111838cab3f47010aeedc1367aa77cf44743c6cf49726ddb96b426cdbf6767e462f940638879805b04dd97d3bb823f",
hex"38c490e3f4f29cc7af8620002fb497591e043377d19fdf4c9cc913600a4d7ae2842e538181790fe7309c85c845b360eab73c8eaa1068866d1a42fb3afb54",
hex"d2706bb65ac8e1c2a319ba53a371d97dc237132b22ce4f7439983545e37164d792dc6925a3c7cde855ac824871c2417052efa103e5b53ec49a2bb4ab7cfc",
hex"36285ee1c0b289eeedf05c9ab66a7b669d92bd3729082c1c42e443d2775b3be7de74b1c64e0cebd0e3a8cddeff2e9acb1ddb62cbb73166723cae905938",
hex"14cd98e3f4f29cc7af8624250c5bd14fb5a69be8235748909e754ef43b09b1b424b1bba062d801f8648f28fb1101b9a56dcb1f69d5e1ba7fe584f6a6be",
hex"fe7862b65ac8e1c2a319ba558513d97dc237132b22ce4f7439983545e37164d792dc6925a3c7cde855ac824871bd455f2859298456da3ade87d884080d",
))
val payloads = Seq(
// The sender sends normal onion payloads to the first two hops.
@ -459,7 +459,7 @@ class SphinxSpec extends AnyFunSuite {
val senderSessionKey = PrivateKey(hex"0202020202020202020202020202020202020202020202020202020202020202")
val PacketAndSecrets(onion, sharedSecrets) = PaymentPacket.create(senderSessionKey, nodeIds, payloads, associatedData)
assert(serializePaymentOnion(onion) == hex"00024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d07666a78b866fda75eb6a991f9815c47624f46324be8a0d8cbbebf25889553edd83cbc0381ce1a5250b59f956b78e1f28ba64f1e8a77aa103ebb2a5f054f3d9271e7bf2f0cbe7c4dbd538fe2977817cb18a3dc52a3e8651a39e38167df0261b67f1d371cb24b39aa2bd3a99be0f16ac186e5d5cf2790d4f60f2e505c64ffa041f74d08b25b7b97e08daeb35df7fd9caa432b0187d3c2dd7f13de35401f79c480404da7e54739f8905fb30b0811c6579e1064182af0ca67e9eb0144796bf347135e90f17126982bc10b91c04e57e736d3accfc7e0afd5945cf8c491c1fa2faa5c3eec70568b6c2514d203ad277f5070d83f30474769d82d26bad5fab11fec659774e30fd9dea7d51f58845510b6765ad8276556ea7f8e8ba10c93991ca404b84b6e30c46cdbd4d5879fe6d6f2df60b96ef4640458be40171b76f33468b0b122b17d0dc165cb60feb41bebf98bcbefe963278c29c7f5885f3d47051888f9ca81ce486b7102572d79109d861f1da8d5a2e810f31b8373ccfc5370169a72c2fb9a10a14be97e2ac55cf27623779e27d48aae14f564b899b260ce69bcd06db4e04044eb400d894d6e6f381abb48c350588a069a72a20a9b686db068fbe58b02909de83d08a8f325a2138cca22649a9944e745f1bf146401493e53e1bf4c5a979922e2a1990f9897376c3597e81c71420f8dcccd54adb11d3483a7cd8a9ae59f3b7f97aabe16805f721403ae88562064e29a7d8c6f39658e15771ca6905aaf31d8b17271fe046033024716c1c12df9a042ab56aa3147005e0f6c5430a7b15bf3db69f705e47735bd4c6815c080b822e70a9177043e4ccb1b972b645777f614f7ebd49f18b354c06cfab44fa67e487d536a77555ba1953b89e53499203d268aefb712520b8f1a5b734ce16ece6fe3250c44e571e86a8f5877a6297aa0b36a84d7a1df571878224a2d77af58652e2e83211a2ce09845181f43ff8b9edf58ee3df045bf91afed92d927b3e4cfc3887255d14c21282ef58f5d68b6d9a872125485be0345cfd22973d75717c2c07f11962971c2b28c0f3dab672d59d5c8ec0f0746718f2966ee1444c53537ae9280dce2cf945d7ce59e2000d6fb8f985fb107591492eaa9e0b24583c445a6c959fe309c4d814ec31f5ab10bae2cf12c3fceb34e724a17c34ed2f04f133d604b564db0f56a463b7a9f453d8ea30ad2c11237d47c8161f8e532e245f4d129ed96afa78c7f9c18ee624e9a593639d911b00ea24923455022ef852e07d0068e27c93b9fa5c65facd2a298b79118405a037ddcc97c8f9281088eddfcaa3a10b810c92d961e3eff6eaf45a81da8593a2252bff0bd41253fe4f35b233553329be00babbf1c93b2a716f4ae6f52cc99018b2d45bc8a0d6e9679b16295a8a43e4d38ebfc31a8464115c31af4588579f6fcf065e6a6362f9237681333fa72a3e881ee5b65abeac5b00555813bb6de0e2b37978e902642cce7e062fa70d042ea668480edddf1a31c91faa67187425a025b938112be61d36c637d8e75e740d2ad542507df80bc2dcb48d5125571f360ee142e300833bd9100e564e84b1d9ef8be88dbac834991d2ae5e5fc217cbbe341a4a58b5e61e0a5a2ea6144607b162fb593c8d73f2d8baf7314f966b06dd2723a43d83645769f45645777ac259911115c29d5459e9001b9622486c533a99c0cc8ef566a96457643d0d3a5ba1ec45037a4dc78906ae3def722eb1b21dc9b0a912b372ed28570ca044f4c73fe7c40799b8ad6afc2d3ab2eee14a5ca0855cf452c12bf5ed4b46f1294406876eec5c48aec2713b5e6f24a44472c5ea6f1b83337e960e4a811a4547484e9f42e3c8507c1070821900b313f2b6a45632db9647cdaf595165afc5ca")
assert(serializePaymentOnion(onion) == hex"00024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d07666a78b866fda75eb6a991f9815c47624f46324b3e437bb0bd12c29a779d62b7912677b490268f80b9e05044c726b1744e50d20777aa103ebb2a5f054f3d9271e7bf2f0cbe7c4d0bf1e53e911040a52c78dd545aa034b026618ac8ea390ae606baddfd5b82f1fc2ad3a99be0f16ac186e5d6e02d98d4f60f2e505831aa8563d86a7f37f10c133df59201f2d288347a64e4a11a61bc524372ee73179179a51809330e01dc38bb5eee8e7de92885b52423493a326f8bf4c4827760a0af90ac6c4e2f91c3ef9e079523c0262ddc052aefa4154f6aaa814ee8b44b17e9d30650a61076c1a4742fe755694923c78c50b3fbb5549aa7876c797f0f48c929c5ce3742db691d66d101e31426128ee1600b3e0c500c9f955d2ae07710842c23c1e1b7ebb6ed428605f35062fed12f868ef735d1d9d6eee61fc722c5797d886b663400e0fd868898a21fbea928c7382ae82a4016e31fe83e3276b9ab95016d32c6318c7fcf859cf1fd9f02c0b2622dd83c961051eb56f10225297154c5b3c535951749402ea57ca8f6daa5cfaec1e08a15badb4cbae156de04d5ba2ce5212699c5fb11ba3307aafab4028963b41a245b9831035bab359ead24ef15e4d50573d40d66fbdedb1ca652488b96e78266f4d4679af93d685ab9519b1565e822d88a69af3e9f3cadb94619e03ce9828d4c28633b992434d23930e2ee943df0229c57276d9c6a977090137544ea48637eba7d6eca4c5fc7bf827658a6a1944a3d9320e549430dea871bd449d6e971cceca7bf48fe855d1b84f63f7cccf3db81ff4c1626f76084b37c95575cd5aa484d34d9129bbd70dcdbc43a7eda6cef758919bbeee00ff16dff45c7d156c3dc3f928949399398a6eb7fa72ac1610b603cbe73d47c7514d28aeca457678b2748c473e043bc1505df8a8e5836b6c8585be7d18ebb24962311e2f46336abff9db3153c56ab2a5af3722ee4128455ba18fe1bfec545a9b0d043a8cf1d5e36cf7419045aed571c1caab08c8f31c773b1a4fd3bb4eee634a9a9de27a2199d4d90fd9ddc6a89d8a3c27b3229653cb076d8a1e867d4ddb02983464797157736e7e635b234a11a0e5f89ae968b2dc6ca39d62d67274a2bf4b86fdfc249b76bd462185703ee5a0edc5d1662a9cc2d2e7a0badace2b4c3b716c6cae7ab5b976ceec3f15ff3f1af849dc22de2a67d73204b21738e74897bd983526bab2edc4825efbbd060675e1858d866606a79634456b2ff89d07166d4b656684db9dbbfa0cb9a85d2a693e1555f05d923768925c8beb67ecbcb4bdaa0028100a84e67e73de06e3fab255d0b1b87822503b17872a5c14502b87d0281d7830e4989659135735677683d8e9f5555a42a6ab8d22347115f254266332a4e54594052ca1afd0475e47dc8ba6bf6c2a381585722949e7ef102bcd68e181965322c5780f66570528b408f00af716c89b8d82bc359f007dfe7c32ce7e44a760a08b97efe9353a1902ba38058f87b90af99bc88ae488d0ad31ffda18c789854dd1e5bf57726b1eb691b4a4b664d33dc225d1242405361d23b3e5d9b6ad5ce3611f276b29a7bf3307326f5f3016f522d513a0d6e0b10280f846e7f14bb365680fd1be66495f49c7d0dc5c36d7c7d845e1c7ddc36a4d54b0733ba9ba3c881f84ed56acf38104eba5ca0a1078c9ee6ba2580f24ac33334cb7e46b9e66925ba5b7066354bae63bb5b79ecedd25a0ec439ec9246fdad77aa1b159741a34579cd7aa237a83f3bbf9663b668024314c6d707a0e25b01808410a3b75c4fc5e2ce04f4dd87e0e8fc317199cbc4b32ba1256ae6138a61936becc4fa9761515b3c2c86372d30949f2d5f89e89bbb6ca708ea9568b58a98d04e219ac69261c3c3dadbb7457d")
// The first two hops can decrypt the onion as usual.
val Right(DecryptedPacket(payload0, nextPacket0, sharedSecret0)) = PaymentPacket.peel(privKeys(0), associatedData, onion)
@ -501,10 +501,10 @@ class SphinxSpec extends AnyFunSuite {
assert(Seq(sharedSecret0, sharedSecret1, sharedSecret2, sharedSecret3, sharedSecret4) == sharedSecrets.map(_._1))
val packets = Seq(nextPacket0, nextPacket1, nextPacket2, nextPacket3, nextPacket4)
assert(packets(0).hmac == ByteVector32(hex"9890f3263d32bccb63a0e1dd1b0db6bf63fe418a0f572ed299d98d343619f098"))
assert(packets(1).hmac == ByteVector32(hex"aee30ae716b93ab6782b907b4cc996cfa3e2219d0a32a677fdeff41071fc86f3"))
assert(packets(2).hmac == ByteVector32(hex"9835e7410219117010779ec0852af38449bfa6a1a610c306cdc7eed8717ecdc9"))
assert(packets(3).hmac == ByteVector32(hex"c02a8c2e221e03f2e2d15266d5838c7f2fedfc1c4467a49d362896dcead60750"))
assert(packets(0).hmac == ByteVector32(hex"4e73505d3e9f5bd9816e6eb2b697c28a3dc29c5a0328ebfd261ececbde063c15"))
assert(packets(1).hmac == ByteVector32(hex"1841603b10d16dd84cf0917db581c765bc602a323f09cd2784481ef198354ea5"))
assert(packets(2).hmac == ByteVector32(hex"059d613df54e969758395e643aabb04276b6fc64e01d5a4de63ec72dfbfb1a10"))
assert(packets(3).hmac == ByteVector32(hex"27c80773d5ab54e0b1ff0b068348394533d235e146e25db69236d2f8a580a919"))
assert(packets(4).hmac == ByteVector32(hex"0000000000000000000000000000000000000000000000000000000000000000"))
}
@ -583,11 +583,11 @@ object SphinxSpec {
// This test vector uses route blinding payloads (encrypted_recipient_data).
val routeBlindingPayloads = Seq(
hex"0f 0208000000000000002a 3903123456",
hex"2d 011900000000000000000000000000000000000000000000000000 02080000000000000231 fdffff0206c1 3b00",
hex"2d 02080000000000000451 0421032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991",
hex"2d 01080000000000000000 042102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145",
hex"2d 0109000000000000000000 06204242424242424242424242424242424242424242424242424242424242424242",
hex"0208000000000000002a 3903123456",
hex"011900000000000000000000000000000000000000000000000000 02080000000000000231 fdffff0206c1 3b00",
hex"02080000000000000451 0421032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991",
hex"01080000000000000000 042102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145",
hex"0109000000000000000000 06204242424242424242424242424242424242424242424242424242424242424242",
)
val associatedData = ByteVector32(hex"4242424242424242424242424242424242424242424242424242424242424242")

View file

@ -15,10 +15,10 @@ class EncryptedRecipientDataSpec extends AnyFunSuiteLike {
val sessionKey = randomKey()
val nodePrivKeys = Seq(randomKey(), randomKey(), randomKey(), randomKey())
val payloads = Seq(
(TlvStream[EncryptedRecipientDataTlv](Padding(hex"000000"), OutgoingChannelId(ShortChannelId(561))), hex"0f 0103000000 02080000000000000231"),
(TlvStream[EncryptedRecipientDataTlv](OutgoingNodeId(PublicKey(hex"025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486"))), hex"23 0421025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486"),
(TlvStream[EncryptedRecipientDataTlv](RecipientSecret(hex"0101010101010101010101010101010101010101010101010101010101010101")), hex"22 06200101010101010101010101010101010101010101010101010101010101010101"),
(TlvStream[EncryptedRecipientDataTlv](Seq(OutgoingChannelId(ShortChannelId(42))), Seq(GenericTlv(UInt64(65535), hex"06c1"))), hex"10 0208000000000000002a fdffff0206c1"),
(TlvStream[EncryptedRecipientDataTlv](Padding(hex"000000"), OutgoingChannelId(ShortChannelId(561))), hex"0103000000 02080000000000000231"),
(TlvStream[EncryptedRecipientDataTlv](OutgoingNodeId(PublicKey(hex"025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486"))), hex"0421025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486"),
(TlvStream[EncryptedRecipientDataTlv](RecipientSecret(hex"0101010101010101010101010101010101010101010101010101010101010101")), hex"06200101010101010101010101010101010101010101010101010101010101010101"),
(TlvStream[EncryptedRecipientDataTlv](Seq(OutgoingChannelId(ShortChannelId(42))), Seq(GenericTlv(UInt64(65535), hex"06c1"))), hex"0208000000000000002a fdffff0206c1"),
)
val blindedRoute = RouteBlinding.create(sessionKey, nodePrivKeys.map(_.publicKey), payloads.map(_._2))
@ -32,17 +32,15 @@ class EncryptedRecipientDataSpec extends AnyFunSuiteLike {
test("decode invalid encrypted recipient data") {
val testCases = Seq(
hex"0a 02080000000000000231 ff", // additional trailing bytes after tlv stream
hex"0b 02080000000000000231", // invalid length (too long)
hex"08 02080000000000000231", // invalid length (too short)
hex"0e 01040000 02080000000000000231", // invalid padding tlv
hex"0f 02080000000000000231 0103000000", // invalid tlv stream ordering
hex"14 02080000000000000231 10080000000000000231", // unknown even tlv field
hex"02080000000000000231 ff", // additional trailing bytes after tlv stream
hex"01040000 02080000000000000231", // invalid padding tlv
hex"02080000000000000231 0103000000", // invalid tlv stream ordering
hex"02080000000000000231 10080000000000000231", // unknown even tlv field
)
for (testCase <- testCases) {
val nodePrivKeys = Seq(randomKey(), randomKey())
val payloads = Seq(hex"0a 02080000000000000231", testCase)
val payloads = Seq(hex"02080000000000000231", testCase)
val blindingPrivKey = randomKey()
val blindedRoute = RouteBlinding.create(blindingPrivKey, nodePrivKeys.map(_.publicKey), payloads)
// The payload for the first node is valid.