├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── README.md ├── errors.go ├── go.mod ├── go.sum ├── spec ├── pbkdf2_sha512_sha3.json ├── scrypt_xor.json ├── triplesec_v1.json ├── triplesec_v2.json ├── triplesec_v3.json └── triplesec_v4.json ├── triplesec.go └── triplesec_test.go /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | test: 11 | strategy: 12 | matrix: 13 | go-version: [1.21.x, 1.22.x, 1.23.x] 14 | os: [ubuntu-latest] 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - uses: actions/setup-go@v3 18 | with: 19 | go-version: ${{ matrix.go-version }} 20 | - uses: actions/checkout@v3 21 | - name: golangci-lint 22 | uses: golangci/golangci-lint-action@v3 23 | with: 24 | version: v1.63 25 | - run: go vet ./... 26 | - run: go test ./... 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters-settings: 2 | gocritic: 3 | disabled-checks: 4 | - ifElseChain 5 | - elseif 6 | 7 | linters: 8 | enable: 9 | - gofmt 10 | - gocritic 11 | - unconvert 12 | - revive 13 | - govet 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Filippo Valsorda, Keybase 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TripleSec 2 | 3 | [![Build Status](https://github.com/keybase/go-triplesec/actions/workflows/ci.yml/badge.svg)](https://github.com/keybase/go-triplesec/actions) 4 | 5 | Golang implementation of the layered encryption scheme TripleSec 6 | 7 | A fork of Fillipo's TripleSec 8 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | package triplesec 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type CorruptionError struct { 8 | msg string 9 | } 10 | 11 | func (e CorruptionError) Error() string { 12 | return "Triplesec corruption: " + e.msg 13 | } 14 | 15 | type VersionError struct { 16 | v Version 17 | } 18 | 19 | func (e VersionError) Error() string { 20 | return fmt.Sprintf("Unknown version: %v", e.v) 21 | } 22 | 23 | type BadPassphraseError struct{} 24 | 25 | func (e BadPassphraseError) Error() string { 26 | return "Bad passphrase (or inflight message tampering)" 27 | } 28 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/keybase/go-triplesec 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 7 | github.com/stretchr/testify v1.10.0 8 | golang.org/x/crypto v0.32.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.1 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+4tLukHoB9iqHOu3LmLhRmgUxZo6Vp4= 4 | github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 8 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= 10 | golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 14 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | -------------------------------------------------------------------------------- /spec/pbkdf2_sha512_sha3.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "generated": "Mon Sep 16 2013 14:22:47 GMT-0400 (EDT)", 4 | "vectors": [ 5 | { 6 | "key": "a61591b91e01468859da", 7 | "salt": "e03b66c33e10d7cc", 8 | "dkLen": 128, 9 | "c": 128, 10 | "dk": "7b10468d541ba5c3c6c27cc15e1c342776f9621cdc9901f3d5866035c318a7891250244bc92c3b5d633d53e3f6d3679c22c691cdb84c29cc7baafa494d519d7568553bbbaa5c9e1f815bb3c5607b185b5395b8d3bb11c86b6a9436a8695c00a4d357f4c253b308bc783aff1851026ea0300b3e5be0fd1c7f82b45a0ed31bc166" 11 | }, 12 | { 13 | "key": "b0bb3852defcd9cea0353ff05f2f9d53dc28a5cfbbca963f4e95051529fff446ff814bf00a7c133c", 14 | "salt": "06755399bc1445c0", 15 | "dkLen": 128, 16 | "c": 128, 17 | "dk": "291ebb9e30ff84601d7783095d1c9fa9966c57a181cb00b9fbd27dfd4c6926851aede82c509f0980631779b2d4eb7b0e55fe166ab427d1da0ec2f042ce2c829d4c33bbf96fc2bf38808a827ed75150b7a63a0ee8b5bc1e26457385b16a7cec7538c988671e129976ef8548deb4289bdcbd62b2de98ba2da9a5252e24da22a151" 18 | }, 19 | { 20 | "key": "a6ba09641ad3240ee9fd7502e04cd8d8361560278fa5bd12fd6a032b051f07ad3d81daca915248d39927b91d9f64237f62dd7a88b121be9ad1920f613dd4d3414d1a0da456d651f9ab6394f19b70fc39", 21 | "salt": "a29e148d711bd1c4", 22 | "dkLen": 128, 23 | "c": 128, 24 | "dk": "61a3e6f7173b1ea93d20309191bda1952ecb9a042d4e3695b99cf64b45521674408f644082525235ef3d778cc2261ac41e057c29668736ad71b605cb8ee599a0f65aa9a58c42e9bde54a24c7bc63618d3b5ec9b5ba4e4961bb886ac4600def512b92041ab28f1cd7e29fe33126d88c11d7dd4e5beef1b013033c89a04057bbb2" 25 | }, 26 | { 27 | "key": "21b45391b878359110a3cf9d1121619cf761b83cbbfee229624a5deb360c66ee90031695f0e3a0d70048f7cc477d733142cad092945b2e7dda7ddffb9aef986913c112758c6f436d129ab77aae9370ba4f276fc7fcb23730533074897d081b0ac4b3b5c61f2958161276511e50ede87a15dbfee46f92e35e4eabbb9f025b3f188919a976a7b82c87f47cfbf6b3bda02d4911333ce7e39f346b3fd5b7338a4983", 28 | "salt": "c80864b61683669a", 29 | "dkLen": 128, 30 | "c": 128, 31 | "dk": "f96209d38bd1abf94588da364deeb172cd5521bc5119bdf9684e04fc41b5b89815f6a1d33ad59bf104e0212e54b5c60d7f981671fe6ea5079364f1d1c9d58277f5065eebef2d3bc5a0a4dfa21399110671dd03570ed99498b5bf36b81c96c767ddb0fdee745669cf1347730efb2524cffec0ff9872bd091ad3d167bbec519cfe" 32 | }, 33 | { 34 | "key": "01a7b65dae6ae302ea99", 35 | "salt": "e08162f86caf07f594838532ed343dcb", 36 | "dkLen": 128, 37 | "c": 128, 38 | "dk": "c3d15f0eae2f714da2bc569fa4f7d2b09b8220b94b6dc234735540225f935c0e95a0588eaa33ba22d2205c55fe4ec87c07b86f92ae26c7724538f719e16543fb9a2c941c8ea45d59b4545986710fce3022f53f1ed44ec7db88b441d872b787db66564774dde93ffce3f3ab4aa8f128845f757e28b1641d98d91e7c0572ccea20" 39 | }, 40 | { 41 | "key": "f8b5b1411c06862d82823551b9777936e5413ba4a16dece24e9859f23b83a39e41fb1fe06f44bf6b", 42 | "salt": "e8a9c4609c86a6ddcaa82e6928863d3d", 43 | "dkLen": 128, 44 | "c": 128, 45 | "dk": "462247dcbf03bc78b30ac670a45930e15f8bc1b60f75bccb80f49ebe3f9dd413049575d9995f2576542a75cbcceb9dca60c939ee6ee3911e553bb6d0a09d23428eb42ea7e6616bb908e1859ab680899f442f263f2ebdc9e05152dcc78351f9be257cf56f732d3acbee41829c0cb3640247f0ac1ffb57008147e58228744765a6" 46 | }, 47 | { 48 | "key": "d72dd8b6519fc1228b7850a801ca9da649cc6d40fe7b0684d672bd2d85e625c845489e2f0394993b6ecba372680432fd942b54e10cf680206943886280e06ed8ce8d12d4869330a64807ddd9a4447264", 49 | "salt": "96728d74c23be5528536bb1d3a13a27c", 50 | "dkLen": 128, 51 | "c": 128, 52 | "dk": "87c6f8ce2146dd578344f67d0cde41503ce71d3b6fc31463ec2c38b1f94701b4ee81b3c13eee0337445764f8b8d561e35be9e6560b9c6f3a5fd4264e3310288c270c7a81e41d68a22182d35a46e7d5b058cf449a4b706b7e1c91d203c7889c0c186ab20e1b14e7029cf3800458dba4fa98653a0ddca9d1bb33be789b15628836" 53 | }, 54 | { 55 | "key": "2e1b1413149ef9de93d5f5a0badc7943af7e3556cb47b099be0f9c51ca7ce467c777851849e96d93294223688b6bef597bfd4bdd1d1fadaa51a760e2b18d444f4326c4735f8ec16caa62a8b37e1c535b6fe00926d579d91be6db3bd71a306213301bffce31dfac012084ff4d632a54de6f0d6562d0970455d7cb80ea4d9841b3b1aa0fe07f8c3dbbe5778b42588a9992736bca91c3e64c2172870dc66acba72a", 56 | "salt": "3f415abda67b991b3b06aabf1d38bbad", 57 | "dkLen": 128, 58 | "c": 128, 59 | "dk": "3795a466458b5224a84aa416293b94a0b7c8d733998c222b9d9de0d2546eeb91f2ac1ee0acfcbf5299c283798274112dc94aa762789058f900436c4b6135ee85476bb7bc681b86ec44182dc6b8a03630338773401bbec16bf2623a21670f19a263a7f20805655a7b50c712eaefc79082e00d5ede187d6118f6c78fe919b58805" 60 | }, 61 | { 62 | "key": "b9d6d87ebbe932f4dbf1", 63 | "salt": "9ab35d8614e09d2b", 64 | "dkLen": 512, 65 | "c": 128, 66 | "dk": "47358c39d7fd4f0a09e2e9491bcc7a48d9aacbe194dd8ea87cae518ab46b355bda23bf2e31c1ac72972263906e35e31fdca418055820ffc1d7a947217bf603472286ddc0f3c425285e791a315f9a97b0aa7eb37c4e7c2d174bc3d63b13b1067530ae4d7e48d45bdcc4e736710288d6c980b1ef781f99ed3a4c37bf1f7f0931e337962762965488f1d9de6400f371151ddadb158800a0a2a77d34aaec7e67e61ba2498dd36c83d4eafbd3d671b3cc2fc032a0d3de21d850e001f6a418c98b85bf542e64342e4956cb95015d07767e6dd5cbcd532ddb0dac58397a321928df1ad84bbbceda0cd1dfcfb8d00a4e3f5a8149d3331bb35f490fd633b27a0ad35cac36d6b4f93bcc9e08dda9eec2567cbee56ee7fe58c8f5c48deac8de45499b1d6d18b143f8f165e482ec2dcf721622526011b825bd10a619fd141e8fdbc1d66c7e2fe7c31daa8b04a2ab4ca496145ca463547f9c4cc56cc4bc3931b5b9d0d7057ffed597ff9f49f491c00e5947634469fd4be21dc64963f02c7e10860dcc17e2ff8129d4ba7c1628600d7d84a633d7eb9d8eb15ceee4ba2f343c4d633b73865281612c1ce95e4ef61cb257c5c94e0c9e4f937c41b4651c972984fc23f6277deb496a8baa94a62aba5aadf1cdc260bfa53ef71af8b389b5b4f42463628c61309fae5aa65f8caeef9fd03019d63196666b8be3bd46b5a517ce48414dbf7f66eeff03ae" 67 | }, 68 | { 69 | "key": "ffa4767b766e70a29388f5ea6fffddcb235aeb826fa47d1264f6b8a70063b738c633ad2f9ea2f270", 70 | "salt": "a79fce4b13190606", 71 | "dkLen": 512, 72 | "c": 128, 73 | "dk": "5c3f8d72af1b0777d7517a3444e19cd73cc7f3dbdca5d648b80c6a2f082eef8e0f53865f824e64a7ebf5ba3d18bea92bba4ee87ac389a5a62bd633e648b860349601978afa220de1dbfdd1e13de6d5a6b3ea7bad9e4a10770928656ce92c43a32c44061ce5c1dc1e87b6c6fb328fc934d1410cb728bafd9920933cc230ddb67588418f7c7e649614be60b7cb21a2227669c75f742bfed657c996713b10d1d633216c39c32d11060ecf8e0489af1f3d59cf4dc473130c6e1edfbbb1393b806c6f00dc3192c2d016d77b0eadb5fdb4834c1f99d95c7d13a71d6e3b5daff8f112f92472483a27592b3d728d3c18af42f32384f2a069839995adbf9b9b1e2b5dd4654c6cbdfbba3504137ebf9f35648f7499017d3ad1850e21e482ebead090d63bc0694c185213f8389855fa907482fe458d0c2ed6e8b8a69573fafa8bcd5967b19d7eefa91937d9bf3268685de81e8e2600eefb526c33ba126540925250e31afa064d02ff65fd53530661c86ec20dee57e9dc20a6b5a62fd0497ce84a49e3365dae1523dc1c5bc7b31d33560d39e777c3f2fb6e10d9f5ff14008b525b454172768db0410a87b9e740eff1021a69ef2ed2fc182b61229b879bcd73618515ac257768700c3855722de71f333915e580e83f48c81dd46204e1de761f77a9500e87bc72caa48997e0beef38b58e1f42335d439362156e1e913ec88a0dba43486789c730" 74 | }, 75 | { 76 | "key": "fecc6bf5a320e2ebd3db960d9f1c829100e7b74d2cd37ecfef83f0513ee7920163111545362547bcf5bcd8af9624194e90c4d365def6e1b2ba61a2f23302575e30fc542467c717b8d84ece08d141d5ef", 77 | "salt": "4274623b4c11a643", 78 | "dkLen": 512, 79 | "c": 128, 80 | "dk": "514d7962088e9d08bb54a31079be7e26a3659e44e41064a635ab797c129b28f2a76b9cb45184f49bb508e1f59772f46aa79af331844fe09cfa45dcbccd307efaa1555799f0c0b0e6fdebb787860196684ead41e6a8b6b3d08f3aa5fa1bb8f4c516774d0bdf7481a7ec87e277a7589f06af6853e5fb3e3e3fc179d6a9fd2c00f5b8cb5c7a89a41638bc833be78a7648d56055e97f92331ca75a96c6b7c9fa2c626df362a4dd23783edc11252eb8512245eafce40047ce8b818c0985a7e65720a3038bb01b4ea904eb6c80e781fcd66ec3df8dbd72af72607a4d641577fbeaa97e855ec93579e34d154e8fc13b1b83b06418be1d16938a9437964c8b656745418bab0facff513ebbd135a6880d58bc7a0f7abc67ee04355fb364d35effb55db7a8e7a19f40b66cd8f3aa585cfd379f1720794361fc6dc0fb3443e286624d011ade86cd83055330e2d1d0b8961aa8f2049b0623a59bc040bc1998a49a9352576a25f8e6b3d335e7885e6d1b79886c1367e555f7f858386b2a7b51c9152e1765a972c7a6499660a0b132bf6ea026e869ca806e0b0c1bb87c68831a432a52f254d36a618d44fdc1f5641212979604c028ba1390bfdf69229fafe9607559ffdef9bc3540233f06ee36d28e0c3e46597dc23d7d54d1898da2e0c9f22d24bd05cc634f64859ccf379094a384188edb96e997772b3ae6bbaf538ba885df563fc822980ab0" 81 | }, 82 | { 83 | "key": "a27ac4f8e4e3508ff27a42a3410c4a7c582516d7d7b64eeb9293ff6996dd46efbdd9960797af12471277f56a66a7124af20e040d7a1e2857f4be85f7e33de8a9f8e80553f014c31bd9e36fba7788ad6585508a710e522297304c0d9c2f77d72bc373a48150942e5925edd364728293cb41ca3efca45db650a0244f8a62322512a8cd04f4e3e03a61b2f0274547fe181be2550d298bb92df4e100696ac74f6441", 84 | "salt": "a6c5cee290e3a3ee", 85 | "dkLen": 512, 86 | "c": 128, 87 | "dk": "7eef09f625ae1f0335181d55d47ca700500d04cb22c55ef79c70889b714ca4e0e50284f04e785998c21f203554b2b571c65264e8202c31907d860bb80893b6c0a5806276dc12a1bd53792aad969b677b92f116be461ea6654319ddee3b6d37597471a5d80e6fff82195a69abc9a90cd295db513fe6910a9372e778cba6a61fbbc3183765f54481bfc0b4372d34cea5198fbc1a1d3d051197388fd0c7953383d9ff8aa124ac1a0d323badea0b29d9e86cab819a7ea89b510c04e308c4d673a596fee8b27ddf47cb11a632f428df422bd820afd4840660880f1a0e1071d11f1c2283a6fc8b3d534930251ad26cc6147b32c4371ab6c0207302bfff52625e9eb186496991ff517d6a4ef998829bbc4df33467b376144a9a804e4c748f0523e60b76d5b84215901c293f437fdea2d0b44e30b1c99f347e8e92b6ca19650f8e05b91277008448a3e64f42e4232ad693ecb0a95bb316c32b4d7abd0735efc519f1c0862dd15a79ba4408f4e1f8132e6bbb2ed37a36b21dd272636fcac02566a7f00243fadb462e23345cbae17eb3738043dfbb3c6845198a79be888028f7baabe1553f1c7f4a885c0b0c7a4dc94ccee8a08628670a2c5da86b848b630dcb72911e262c3ccb59c4c3c60476e0c776b29f3b5ce0328d64f9dbf6d718250039cc8cda33af1be758532416b7838702d4f1da3a643eeb87814f86377309a705cd75b99e5449" 88 | }, 89 | { 90 | "key": "1486d24244162a76f1d0", 91 | "salt": "76c67298ce61a167", 92 | "dkLen": 1024, 93 | "c": 64, 94 | "dk": "ac5de068de11246c7e89d40013ac09a91fa9cc48ebc82ae3c4a555e05f91265af59f3484796cac2d70b182578f92a18f7bf4ba13b134f5683b76def9e2928ef4e6a2edf4f3263f99e3a8fb4138585a2782c7bcda0d511f8bf6a556d919b385bdd44eb5b09c5d8384b44eb1d9620090a4b469e6a710f9ad27e3b68c2e159f765c89ec5bd6e4b8b7e0c1fc4fb59be929283642caee0100a6a22ae3cf49527a5890dd85e1b4e6ce266d848af589fa3568a1e8e9d7bf9fd7db11b9374ceb846682036a1f27a0b16000872dfab437782a8e9005c6d9b13eebcce4a27184dedb8d07e58c201b64696ed51afaf284fabf72f8db75fffb2f48bf2c38a9b93d57e2c82161e37a0e6395ee91d4e122827d26715cc9e167b0d443ebab35dad2a88139b0a38a0db2590d529a3a8fbbaeacfc94fe71987ced9674d909911be1473d5a22f9f3c347f56020b9aa6a1df363a3be07d5fd125f4881e6c1d623fadf54c71e225ba5ea1f226478ece5ef66ed85c74552b6e07a6f7bb44a1e8b6e3e314f5b90b326e94a4538af9760348b430d5e01325b1495fe0c947816e80b7ff9605824bd712faf8985c047104cc64cf45026cb20917d6cba9152ae243f9fa1b7e10725677e5e31c27752547ccfda684b9d1b116e14a9e62b96dedf1eaa0937ff866a90a921a1d567c7a486d38180f85676707a7e5121b8000f5450fe79fef769b2451d54327b10a9ec6e635e6639a8cf5650729550af77d0922176c7d3af6b17f19a4c015369a657e491e353a5b8808c962032be712cac5c79a8d641c13ca4e3f8a1b3099dee41c4176667f988a2f1b3279a0009dafaeb2853b96342fd0bb6499eced47e5a2f733e877440c61c0c164452d3aee823a926cae018676faf219518ef0b533377b7073cd42258263230d8dfd441c92e3fd054cd66fcb57862aacdc2e33c9ffafee55568a45d3fe2c066e6a73caf83291bc997aad0e1df5197e2cebb6d000251ac150c814a7f32be90c326aa4dc08e8ee89fd30a2ad7f983178a75a0b55b10e33fe3174d7d8884c4528875e02a6d71125e8b2cf522a54b47a2caecfcea174cafd7185cca15c4f1df1fa27ed1ae823671df5ef9e06b8a9762fd863650752379ac0ac80fd1e430fa67d2994d11c84a715635ce8ce376b7ff61843ebddb431b7fcdb3ac8ada116e8a2d6dbb06dc491b3c0793a03af89fd830c2d37a1c6b5b583160eadd39d0664fcbaceb9b519b7d481a0998e9073f44daae8c8c777b9a0ef684dda6de0639451fe25707d4cf128f7a0e30b73199586f60799cec21a374d3ba50ec71a7faac7b27ff064bc9bd9eaa9ee99480a555c2776209db027fdb1cad41e3ca965bedb7dab2b6ada98d53e05d654312608b0dbda572ea3147bae5b09d5a1c9d21fba4b476df654ea5bc6a3a91bf207bdfd8a1b834dedfa1c6846503d575ccdf29e70f0e" 95 | }, 96 | { 97 | "key": "31a5ffb4085e0bfefcae24914d7ae1a6df51147a9c23d7e5b253ac28ba91ccee08e37bf0bc4ef7a0", 98 | "salt": "f379a572738b80da", 99 | "dkLen": 1024, 100 | "c": 64, 101 | "dk": "b9065d1bf1b971451fa23780af7ad933770132b085256a7ef3adf0de5bc1e886948d93603b5d8272dcb17e3aad6a72f5a9ec7b21c2fda2a92eea18f778b4b3d2868b2a868ec72ef75c4b6d1f6b1821f692e3d48e515997a0766b8664d0d3d2f954efd0bfc01a0ceb2c88bdcafff2428ca4fb13539550faa40aea3365cad94a4b55582b1f2877372585c5893b0d57b2542a004f69784e3c2115baa8d996254420862a7013e2261ded1bb04b834f4d0569bd3f25a058ce53bdb590b2dc0fe1efa0ad6f5d941c29771bf8aa2d964410682734b3b1991268c84d171e8e829def87f928de31ca24ca9cb7737fbc00a2e258a891cb70dc74f2f1a41788a98f0fbadb979936ef277b6b3b588279954db0926c4f66e10a3b6a4f564493883c561d35661b38586a2ca3118cd58cd38b749cf72c036eb34763cdf71b179dd5b5a95a9d57b6e1d7c6eabb1673759d9bed6914312a00001e16462ff62f446fda994ebfecb3642343e97f8186c37aa8e3ed36c3c4c4e9db73c8a2c9aa010ef7a89b1c8b3a9d7a5adfe615abad290543c44854b901223fe5f688187f6619a50e8449c5b6fc6dd8846d3aff27248982ff7564b5628ba524014faa64d9b416a46990a0b774c1bb47fe374dc5b6d886a4293017107680f2d7f422b211dfc046f92d81d65625a89ae78cec2c0a8a4a8a8edda46669c4be1f3b7c1a81a2a3fbfd2c38a14744d186145ac38b8f644f7bdf66559a5b0eabffd5dd82d0274f6a6ea1cc06b7abb642a96b26930738a9a0af3a940f9563bc7e1601ee58cfbef2446d76d2d97f648708589b1b56972db3173aa746f40ea5d395c8311e12c956ec5b2be1992eb78729a0eb852fa50908450153ea3f6ba1abb1e212aed8edad4867ff7b6d6d42acb6bb807022964397b05319bb0e78a128b157628c014038e7a1e0b4894a21ce76961c6c68340de68d8ede194f85adcb9146b3c25f010b8408b214681881ab320ed52f00f6f6706445d56bd0ea73851ed4b46ffa3364c7e1f2bc4a47734a4181812ceee3f5c6d6cb3ccb4d3941fbe1af095e0fabe9a6859755dd4d17ad184f33bbd88c8e466b92935ac6e99640176a39605fb765b7ece56a78b862a816d95026488536042e41691960367a2dad6a69094342f7930f9af553475963bac7e0b8e3673ef5e7b99eadd36ad35c12389765800a250dd195a31e83ac25498a0b7141534eab4c59ebd465a2115c4976c7b4bfa5f84952dd99c18812307fbdd49d475b89a4da61a60160533f40b89e038ceb446d6329d2af3cde63f96f379f378438312664cd09c1db4ed5dca338e609a7fcd32c06f1f2bedef088e68f19da7cc18a5eb968b9ee7a5a08d593f476acbccd0e837181fdcb6799f344459157f4b865bd93aa3f3878c4e418e88b1b6314ba00e4bbb3d0daaa7c3322da36a603371b854981f314e982b6f253bd" 102 | }, 103 | { 104 | "key": "6e14e4f6a9ce0ee4ab1e8f21190ec02d9ca9dfc0917ca80a795eb59555a059905957ce9a498589aee5ad3715225236ff0f924578392abc25b498a7c413a0a973dce71e53da1ad38cd383455ad215eab2", 105 | "salt": "97e6bd8427dabbe5", 106 | "dkLen": 1024, 107 | "c": 64, 108 | "dk": "8e44d7b0140fc6d704c1d56325526c44341127fb6ad98f6db6cfb2fc2dbcd747bf3a8c88749771d61038e302d253f064e30c6b7fcffe471a5e989c287b1dea0976c665cad170f7001d124883c999f9076fbadde99de02f5507225c03e615c1181f745514876e15d0ba63e740fcdade4dd13b748dc84e11a27fbb4509bbcf5ed332fcbb5fcddcccf6bd2397df0fbf61a767e3cc4034183e0c7a65597ae0dc60c3a5b38d7fbde141b3e38920947a75f5a76a317281a968d8e573af59f2ba02e0fc0d93b4908c9b37b659cbed47935dadd87e1388e8fd14bc79ab8aff9b5a54df06b4d46824d01802a7a761df8fc8c7bdc6986d15034256b852e83c44ab0d8cd39073cb32830a90576f16d1c241577eddb61ffbc29463d9a793f141dd529dec93ceebae9a103b29e2dd7824b7686fc7de294df28f47f3df6fbc97454d6870b0b56db8fb184ee50e318a65c6f7515e0e528063e676450d00829604d5b24f25248e2314f25eb1b11eace4d54d5563ad72ae7a1358e236cadb1eda26fe9c0b540b7d1362e4a5f3a9e24c453f37a039d4d48e67c748efdc91d7f31177fb84478f4c83defe899dfcd1f34cd5a83b38e5eb42addcba0a0ad7f3f10d8e106eaadaa77a43478ff3198dfb0f2f2c96cb7b1d9548897dfa75bf611805a22dc2530c1831c6a75f37e0aa0c2fb47f620be7968771cb7f18606b2f49eb7a1917c8e2c21072ba20ed6244d5f1221d266ec052451606f5b7b18898728cee55c89cbfc0fbe06fa0a1068c224e3051f273c4a72a624031ab7aec18410766c18c48e178ceaee1a9584feadb0300a8c3dab1fe5310bd1785881ca9358df89c7cf6674882e4176448a87fa533e1c966c1e5400ae41f9107caeb269b0e7fd0637ea6c28036b7851d1588c8c797ee48b9206263a4d308e2f1d5eb6278ae4a8c1e834333aa64d2eac0739471ff6460da023b7747d10e123949866402c40614129a3c34ff95d45c874b335d15e4d13a36e9106f49ef0967ca0bec081c4e0b0c8d0f249209236f6c0944662b513260b7afc7305a8379ebe6fb071904ab78cf658b831025c83fa2d91d8d52fbf63091275bbc46071da0e4f96059b4838687703aa4f252cb1b5c921a636a10cd8e7f1ca1c3615c6f1e600aef152395ecb8a3820bf1fac49d200ae568f2c8347a7212274e1f6eb5229ab878493d6a278e3d97c366162f97359368a1484fcd6c80b85a1573bf6d2582482a0e21e452ed1f49011c9feb91f01e5623cac118a226ddd1b33bf6377d64985fc3ff5d9967e7adbdc51d3552e362c2fa0d0b0649208d4157c0ba249ab5322490137d7c3f12516a3dd548484e811647dee7627b74d1e90f1b1c4b6228cdea274bcef4735021a96a0374119a0ac7008f3f90ebf5d52b2241e70ac80937435a54502390167f142d509515271a3ec3bfa74ab1b4b1d22f2eca623d" 109 | }, 110 | { 111 | "key": "ae26596ba74f8042533569a380ce7611c16e65443a9c9689ab3dc32b96a26ab597b2523c13273b1b9320366e463d9bf87f9ad8ddf269474a4ed9435eb5e258bc320c4dbc7585b40566f33602bce968c9c408381ec82cb9f0334ad54538af4929e246b961969c2f3fbc3271544e67b9717c5313de4d8c46f4b82b03260d1eebd35c3aec418d1f95da9bdf0e6f188676d8764e1034d009cb1234f1ec25798e4499", 112 | "salt": "f5fd58a09e54add3", 113 | "dkLen": 1024, 114 | "c": 64, 115 | "dk": "23d5ab080065fea5bfde818fd76a9ded4d0a4c86e2f7d8c88b29a8bbe7275e89e9a4bd790e74c86c0ced38df9a83930a8ea1b302717622340b315a5ba68901e10329d90ff4edf8b5ee0757d64f602526d7b198f24fcb8b7b91c1f315dd3a1f5671f4175909da162e4b278662b6632a525a139ec31e7e5d99d129301d05323a3345106785e0f9f0f085386609f6441f21790cb282671ee7bb340cdc141a15e300b63e00ee9183782962ef1248ad7d0a282bd786385933ca368b7ffadfc71b9618f9bd2da76cd9b2e8724ba1c4c9fc20644f0d24e7e21536dcefea91e7095a947a47fe44b4da4a8ce9c37c62ac4e40802b17d0ff229262a617b5e2ebd6ea8e163740c2fd2a906dd4120047c94081da855e4faee426e2563865a5cc59cdf5f576a0740f6c78faa13847dfbaaee41255f74ad0ba6353d6bfe1b48024bc21c251a83b1f97c984be28b0e44ff88737f349dfb6aed0afb5aa3c6bace39cff4996fb9e2e1b96623747806e3a434c68613b0ba17bc4b3a8dc0e0f4b2ddf40292166922cd0423f39592981caea0d00fe3bf0a3458dc8facfcd379f34161538a86b4daf7b5ed7873de0618d4d1c27840a69c476793141fb4f1683c36be57ba037810b0627f7e1f12337b2bfb596e07a4c6e1edad83dbe9699122acd7e7bc3e8ea6fd151100565456ec60d4568fde8bb674111a14d0a76bac799d642f3b1ff0ca401f85b685bb7800d3b1dbc18394ffcddcc1cc72668765895409d12a18f4d1dabc126813fc5b72f968b3a5297a23eae4e81683406859d89708b3b99262eccb58eea88217eb6b0ea27a2449663691b297e26ab53eb7c1d3b3eadeb54e7e06b2d845775b0d520935b1a5f1173668e4dd036ed2f6790b5e9ea8263837ac351051f504ff30ec91ba948190c9f99b5ca19ac8fe82845f1222f8f46c2bb39b1893361e31ff32176f93223ee1835132d809928b725395c692b13c03508e302e491cfeb0b0227b9cd7f5acb07f22aca38b024b0b32d94760fdf89f41ea9a24754f7e7384cdca08e4e2479733c5c767a5e8cb3e6c9b9dd7d0a9f9fbd0c6f564ada513389c3d213bedac06990d480928fa4f72b1bd38df8f8d420288f18bdce7174c319244871ecf60bc1d8584e78dd8a196e568410d250b92284ed9229d524572a8326f1973017726a0638308a25a900d4841e61ecc98121d5934eef724171342eccc048ee0f4b129114ebe47960d716aa59030ef8be8ebf24253ed600ccf45a301e3c552dcc04c48c1c89f91ecd14a57cd83f2af4b978b837dea137bd1591eda092328179443678cba03ef66ac98b8417ffcb95e55188722d73f657724bc18f2cf834ce599a7c3bca45646a223390a03c4d5bd4238bd572168541f5144babb554905425bb20669ef0a1eaecdfab7ca2e2fd849ea26c8e0afad8f5f5895b94d80d80d653a099d256acba" 116 | }, 117 | { 118 | "key": "c8354ed4d8aadbfb75f3", 119 | "salt": "52c2fedf6f22f2309daa3f0563683045", 120 | "dkLen": 64, 121 | "c": 1024, 122 | "dk": "bcb370f1085f637afeb54a912d189dbe88c38eb05d991923c6621486f47110fb7ae7745f95796eb55d443754af617c01c9d4304ee37be06cc79af9f4697d61bc" 123 | }, 124 | { 125 | "key": "ca8da02ea11e096d1ff2b5a0bc7892f11949a668dde64ab325bdfbceb3d17d1d21e4a03e838d0927", 126 | "salt": "05185f2dbb6458345186deea560c140b", 127 | "dkLen": 64, 128 | "c": 1024, 129 | "dk": "43bb7648674056260840731f74915aaa8a5272962b56366578f332cd710ba6adc8cc992cdc25929da3f3acdef4be22f44c62512d4afdb90678908afd2e25a28b" 130 | }, 131 | { 132 | "key": "214b15ccc10813470b57d3b705c3e576c17643000dadc390eebba01507e2110880b56fff788278056f1bfc399c4719e00b7b55cf3f202c8e009abc73af91b146681fd3ab299aea7bd18c74c3bfbe715e", 133 | "salt": "90f39bd4cd820111eb6da99045d25a0c", 134 | "dkLen": 64, 135 | "c": 1024, 136 | "dk": "f12b27a7de105d03ca16f228509eb6c4f7ebfe8d33ec529f37867e7a9d9441f22bc21a80c642177132ce85f265c9247bb52ae3a9c544aa0191052d3b61bf132f" 137 | }, 138 | { 139 | "key": "1aac6eb9fe33fe0efab0c5780992b0c26a4497bcabeea37658be7044e537113f4433cf899e342557027aa72d5c7b6cfb2d346b07d645eac2b855ef620c91ff80b5735a42c24e4c30e18b90727d223530a6a680946a2d81dbb32f9ca73b8f4922661b2c2f26f8e320786a3c0e46dace856ced2dd30860243bf8eaed8cd86e8334b77ff25e73500a823592acf6ddd24133e90fa45db2410532112092226c9370b8", 140 | "salt": "c32b9b5938c656e3c4829c0804278c13", 141 | "dkLen": 64, 142 | "c": 1024, 143 | "dk": "0b41efc5ee30244e614ad30970fba73291d5de5fe631abd64a4ff346fc11b763bacb87426f69ebdcbe6a09f79de7c562b461968c225dbcb9843be4340fdf582f" 144 | } 145 | ] 146 | } 147 | -------------------------------------------------------------------------------- /spec/scrypt_xor.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "generated": "Sun Oct 13 2013 10:40:41 GMT-0400 (EDT)", 4 | "vectors": [ 5 | { 6 | "key": "fa30a9c4357524ff68fe", 7 | "salt": "d8d42da0720796e1", 8 | "dkLen": 128, 9 | "c": 32, 10 | "r": 8, 11 | "N": 9, 12 | "p": 1, 13 | "dk": "8d2d4a23b9c546626df20eca353a3be47acd47aaf7fe06264660490dc51cc3f4a5b3fdef100805f8cba6cefa3d7568ea0e61ce9191098aac56593d76954caa6cd1345c0f4782a38ee2d22ed49397087a784e4b164addcf3f883ab77ffc6373190d69ec2f730c770d999f8cdc4114505ca464a79f421570667fc4695a3cfdd6f5" 14 | }, 15 | { 16 | "key": "c6c7269ff053de0784741855352074668484f32cd6f7a76409163bc237ada16cba27f402f3abba93", 17 | "salt": "f800c2eba807bbe2", 18 | "dkLen": 128, 19 | "c": 32, 20 | "r": 8, 21 | "N": 9, 22 | "p": 1, 23 | "dk": "f0c6ecc5e09011b3a9dadcf7236918b629fb6328da1e01b848aa52ba5f65ccc492a06da238751524b1aaceecf5dc8a3aa51003bd27ac1d54d5d31e5e9d15b0f9a05af8a02de66d3ddf6b4232f57850eb20b839a447cc760c01bcd0f8edcf805d2ef392d913949aa03dcc2d51f77e761003ded2c41dc353f78e8664bb8071be76" 24 | }, 25 | { 26 | "key": "853a2bad6d5b96793763ae273031e1173a4108712c8bc429cfa4206c2c6d8ecbe17aad797ea99f86ee48519a9f2b2bf7dccd54193c0028002ccd023a9ba2c39ca97c6669cedd6727dfff5bae0162f94a", 27 | "salt": "aced38f45e053201", 28 | "dkLen": 128, 29 | "c": 32, 30 | "r": 8, 31 | "N": 9, 32 | "p": 1, 33 | "dk": "663549a559c2454c72cf00f5120fdd7e9e62370d84a0a7f63ad99e001591e8e9e05337ad58dda737fe73c4ab6578f3f085662fed62d2741fb38cf5cc760b85986c7085d1009cd08bcb960f29a8391ff7fdfb418de76163c306ebe90e5d687a2f50be2ac31ca8ef90de86df4ed1633c778139d23814271fae92d80362e057d763" 34 | }, 35 | { 36 | "key": "ab69499098048b7d4a65f6301710c8e2e8dffdae6e7fe8b2b6e573393ca86c3dd8a63d79c9da290c1a28348755bf655f5c50e980cbc02041847f98f5a7636d83c42d206cf69b7dc77dc6bf444675ebde9f2274edf7436bb43271b0390dfe6bbf668045d630ca47d1d852d373418dc30544cbdd4cda56f2fc541375753255b2c9050632746b32368eb22acbb0ca7794eecea813f8f99907fcff82e7f2d4731831", 37 | "salt": "36943b1e696df335", 38 | "dkLen": 128, 39 | "c": 32, 40 | "r": 8, 41 | "N": 9, 42 | "p": 1, 43 | "dk": "a24789fd124c0496316defc134b3a2a577ae503c7bc6897467aa8b36173bdf5730220bbcb7e45c6b6f310583db5f3e8132e6a485c3636e3409704fec6595ade7eeff6655091c73d9ff8f01ac6e7382b63aad6422268c74746b226a42f3582613621c137a07c8c8312f30b1c9396091bb199f12acdb2f67b61b538f55016988d1" 44 | }, 45 | { 46 | "key": "cd146ded4c6afffbe8f0", 47 | "salt": "99cccd1cf1cb96b791eab548c5e2fa08", 48 | "dkLen": 128, 49 | "c": 32, 50 | "r": 8, 51 | "N": 9, 52 | "p": 1, 53 | "dk": "b9b033349fbfacba7c3d8af7fc98c0ad518d16ee0ac1cc28e313cee8e2fac96cc351069b575eb21dbfde01cbf90801b0bd2a6d8050ac2da62672cb856baf537c3e9cce56849e76012628722ff5bfd86efaf4c6f4d1037030b415762cba59b39a2ef75a9ae11a25d905b161b79e6ab6139a9363bbf13a7bb280ec4899b9cc608c" 54 | }, 55 | { 56 | "key": "2186c2a17f3864b6ab35f1bf4dfb1ce63b03c261b5938202e2c7871657f40c144982480c08a5d634", 57 | "salt": "8a04b8515ba2d8cc588830b51fe1190d", 58 | "dkLen": 128, 59 | "c": 32, 60 | "r": 8, 61 | "N": 9, 62 | "p": 1, 63 | "dk": "b080dbabcc6d1b150621b39b2b7c262626b55764aaf4e660e10f910d9ad11331f8e306052fb21c327c8bcce7ea9bb533f5d23910e4b264d6db671f7e9476b72bcc942f5c9216ca3131f69814f445b2b175ee0303240b964ce6eb99be6ff6349d86980acb60c7b93169ddf7df83abd898a799a40c4bf82de5c77fff1e8c75037b" 64 | }, 65 | { 66 | "key": "4974d538883d9e7d5867f310862bf5a6019b8746510f5fa20f9267f0d09851dbb5dcd7e5618858f8426c38e4a2e7b0f10ced23b2ff2c84cd54f3dd1835350b1208fd37d59754a70a930c18403e6564dc", 67 | "salt": "6ff4830388c6e935992023c32602ad2b", 68 | "dkLen": 128, 69 | "c": 32, 70 | "r": 8, 71 | "N": 9, 72 | "p": 1, 73 | "dk": "34acd312c4577b6982bbcc1c13a83c1cf4763b224f3c241ef44e41ec79f4cd74d31e7aa1704e9b6a269a48288d1f906f1575a95389653cd6ad67e99b65e98aab1ef132cd0f21434d37f09901a3ea12a6269d95812fea6e9832dfe1dc03c9ef9297c8466b5517de6f5b1e6c1a883eb765d613ddcd0957813883ff35370b4a2811" 74 | }, 75 | { 76 | "key": "9fd47aaf6281bc2a463245452d83d3ece16398fea43ace64d05956ca4eadcbe088c5451683225612166bf7bea2fd64c7c673f3875d9fae7004db76437eeda8eb2ed8b6ac32bd9f20542c1fef6ba042eacfe7f47219ce23a5471e5e08be75ea44d8dca0c8d29f79e8a29318a47b0be822f15220e205c7b2d04f22f7c2406a555cc5d7bd37baa24b2aca8f6b718528ff764a948751760508e32a55b68eef2421a6", 77 | "salt": "4425e183ae01957b1ef964b0b41daaf9", 78 | "dkLen": 128, 79 | "c": 32, 80 | "r": 8, 81 | "N": 9, 82 | "p": 1, 83 | "dk": "6231c603e434493fc997ef9f12723b586ab366c038ee911e08ebbf4e0eed380464d2bbfea8368f2a61f49d1a58bc9bc5a34ad9ed9510afb48daa97c3e67e1f964cead6400dd95e7a64516041390f9cb3d09a5e0b0318e02200327ded496acab00962bc5d508c39fa78a9838064130ebb41ae6a897b325317b567ed9cd55db82f" 84 | }, 85 | { 86 | "key": "7d435473d977a8b572a4", 87 | "salt": "856d3164717a1ead", 88 | "dkLen": 512, 89 | "c": 32, 90 | "r": 8, 91 | "N": 9, 92 | "p": 1, 93 | "dk": "0bf2d28225a7db7d11cf63992040eda682524879dee630e1efe2aaac70dcb712b53d74869d2c63892546b2c9e9743707369501134f55f737c47ad0773c4cf52a508190d313720eea7a7ea6f26dc0a2d40416df323bc4714c4489ea75b20ad929e23cb8fb422a7bd39ccdf382d076560b1eab3add9f5963c3bc1e2903c6c1535e99aacfd32890a82c75d75fc250051c5b477c4c9df12d196dbc805fdd1b7804d84ba9dd37ac11393bdfbee48b48c850fc9552951af7d8de175f8307f8e0901b8375702cf0bbe27d77903c27adc4c73e1bb8061f2b0e885654882acf3d2c47c58dc7860ef3968da1771e58d44dad05ec76749e3d558a8c23fbfd7b07d99242ecf49f7f76805bc86e8f8eeeec0fa58ecb7c017a2c60e072257936948723185ad6058fae33d35cca3c4e67fe438febb167a4e8d1a4af254aafbce6e5c177ec91a49c08645a8d21b3c129daef87aa5f37296fa45f79cbc2a0c2271b4bed9e689b571a6d785b049fdae4c3e73c3cbb460d1a51d4bb4226fe3342464c28b584d5d9345977d3fcf9e3ed9c40efb5ed55d15f274bf734577eb119a53aa9d9049650bae36b118833bc4a6d3ce30d2de534e288941581ec9053d752aee8b9f8110381503cb1b7552bda507595909a63f674cb383db518aaa8128e837e5682b65934c662b4d6845f2c0c96ccaf49d514815d379a8853d8252840938057c3926d5dd9e4bde780" 94 | }, 95 | { 96 | "key": "e37e400403725bd49272066c6082e6661ada229040c18a0708ac57f13998aa5de4a5d32d2129af1c", 97 | "salt": "d6b84224c25a545a", 98 | "dkLen": 512, 99 | "c": 32, 100 | "r": 8, 101 | "N": 9, 102 | "p": 1, 103 | "dk": "8430ef565b813fea466f29f96e7852eb23c7b8a732ea9fdb0f786a633efce819052bd0769e25cf60c845f787209f6199a1e236cfd70c41a618cef241ffc7a8664d463aac977aedc6c642cd3a8b905ad69fb891bb3018a9ddcc9be222d30fc174b8c6649adee5fe8edfe1261db0b547b60b3e8dda42d5bf481282fe9a9ae8f6e038b5046e888f2b53338f2a251a09ad249b5d696904b426b0b8644f0d4dc09485b7859447eb5996326b6ab14a96137d0bfa2f5469a45e3947f3586f62b816254d815ea8e324cc28b5f2d2391dac6c18eb6c194765706c2c54d16e7e513d488d7a97e409c1d8765bfd7385f60bfef1d0668ea682f6fc5f91cdfd54564d1b967996fb5f7637cdcf9691aadb945f8b4dd93f40ad77f68f449aa40cf6ca0b640975de1b22974c6d489c53f1c38f27f189175b5888251f59b645a3527fc6de0ef13558f2e8c48a266ee8f62cb8d0ca4120f0675ffcae47ac904df34d061a61c29a6a0b86fcc767a869101db9d540c9f047dd0a201348a9e62b955613b41d6a029a77558c2f0eb8eea46e50c7e513b88c675b802f2e9e439bcfbd5b7dcf8c02a7d57df8766ec143d4d302b12cdddaf0e804290b5c91dab22b652b4dd8122e9d0bc849fbca4e8a5c32b67e7f67cd61c397136d517dc7bc6b5318d5e72980782fcf38e1ec4b5a815a5bef5ed93f7c1f812ab9a7e636dc868927cdd1e0798bb4833b19045d" 104 | }, 105 | { 106 | "key": "9f2aeede51d458b7449b22f2ea63097d8bd041e9a1be1dd4147ee2bf80147176e47dbc4087ccd893fe276f078b3bbef10040cb35776df2d6492dcf2959b135a3da06aa7b2fd43e0276761818cc2e1178", 107 | "salt": "1d0c3d2a659b1359", 108 | "dkLen": 512, 109 | "c": 32, 110 | "r": 8, 111 | "N": 9, 112 | "p": 1, 113 | "dk": "d35f3619bbb232fa55a6afed5fcd46eeecd538128afb66ac27ca379c58e0af2d88fc39b5c0705a426196a2054bcf8d3329f984377c2ed7e1cabec467c938c046edb68e6cfbdfaf3d30825446899a0103c7f84378ebb5af990e8dbb8bafba070ee3e6b90a4bc61e537864937f1ba40841b17cc92606f88d2c6d674887e7332d382b14904ee30c276266b8001b120bbb0582394839b9fd7bb6e89f297211daa93ba95f3b25f1f46b4e7e267573249e7bf872206b9ed4ff968907f32fdea379cb242e040c3e1f7732b168afa9f833310fcd6fad13515519a5a78d2a27e7e8d6613222766a154d3b888330d9c04b542e85e8010ac5e8cc24254cc9c5743cc6ec09c4be3b46cf9e75e5c3c7c447610c8b090b2b4b32e5dc4695740f269662145b2c15ac71f663957959db55520cd7f8581c1cc32ccda3ff34678861e50fff8ea86eb7c1b6a58906642c707ef0b19a54a48da9f4701ad216afc96ec1232c55f53a69e2d3ccd582cd9b33b8988e0f6eba349ebbdce53918bfe09e522b390ec69386582482b0ab016e5558f52c02074426e127d3a60479d4ce683961a6c956b485a1e79df60154feb04db83265bcee11bd07c56b973fa4bcfad21ce7a52bf3ab9558e01c954e0270c1219f2ce503b2f0942709baf5491965540ac40dec03e4323aa3bb00c3d80e2a25d612492fd88bbcef83a48760b6b9f4fd27ba02068e2b616661dd5c" 114 | }, 115 | { 116 | "key": "79965911c6c2c21b39b97fe0008195f96e570a6217737702d17aa6a8ee3fb03cbe73fd9e286780df488c7d8584a0b4543d0fccc900a40115e25dc1f0207ae5aa63a112192c0a47135bc75f481733f605ecb6a2cbe937a145dbffba7295aa2725bbd9a77823f1ff0c6346939b0ab4834ef0ef307087d7e82efa6017678b8c61491db2f4262ed715fc66eec8f5b119d89db0e29581da4b0b98fde6a5865422a801", 117 | "salt": "e48ad16a7d1f6835", 118 | "dkLen": 512, 119 | "c": 32, 120 | "r": 8, 121 | "N": 9, 122 | "p": 1, 123 | "dk": "2f4f5975d2624a329e880fbaf6118da10717463aad11a13ec44bd3069ce723ae921b92d3a44ef905fc30ee129ee585c3376959358adf41bcad0f5947923bd59be1f6bd88004f37ced7e7cd59ab4c56b9be74b40d1482e6f792226d8ff12ae21bab02e3d9b0f2def37faa8f1f5d9c811311a8088843a1a06dfa445a9f7d79bb8bad823c2c99beb68c234eca4afc046dd99031f5363511ea78da7e91d32d15ad3a1615a48ee4fe5c9dec603da92a9c6ffcd990fab1f212367310abad952f25582dbee29ea30b8fa7bc17b5280d895fe0c394fb6056dee3d110c925c6af4c64dfb7f7327fcb8861b5d8d64a0a00ac2a4470e7bb0a7728528a880e7e63dfee2364b42033cbf88a03270c8cb90d52416244f552b7c7ad1bab2201c9f5000e8a57f7f7a8249b1f18bbe848e6f25a42745e3b4b99914376734e5a3f0f4c14075a692029119482561a269b50766284e9c354331cad9aad17ddf9fb33bab6dd987d6f421b8a724f5a05924e8e8bb9a043f7a847d782cdb5d4f71b2d74ddc5317974d52cbb0e862a7441ba7771ce84f0621ed757ab6335e6bf93f64dca53892242d4b5be41ff84083e454b5ad4a5cb0063e4e42630b3e958231dee27b70458e2d031bda8cc8ca25601208468720cd9e8f60ac607aad96f06a1fe89c1f094ca703ec132dfe50da20f6fa05fbd8d9b79dc2b543745fd6753a0ead9c1788eed9ebc170ba41591" 124 | }, 125 | { 126 | "key": "8cacb7f93de12870696a", 127 | "salt": "96c985d3f94086f8", 128 | "dkLen": 128, 129 | "c": 32, 130 | "r": 8, 131 | "N": 6, 132 | "p": 4, 133 | "dk": "e284068c0afef3c571aef75492b2cff8547d2603ff7f1dfb607d30eaa7e1b62ca719d181ed1483b55981fc77a67abf5e072c73d9f336cb15ab4dea113868ce56acae5893227c5c864640b52c79a16296d5dfd8229e8c6d6beabd16013c552b55373be13c9e61d65836a9eac66f952d5517d1566da258a570d97f21bdd4d99e47" 134 | }, 135 | { 136 | "key": "665cd7d0ebf106a1972a7e27368ee6dccd449b62345969f90f8c5a939b5d2b7a2757f60900801f02", 137 | "salt": "9514ef3cd02bf0e4", 138 | "dkLen": 128, 139 | "c": 32, 140 | "r": 8, 141 | "N": 6, 142 | "p": 4, 143 | "dk": "36f2050e6cdb520b0d59c14496f3da25b8135f011029cd8e66c2fcfcd6f239ed7ca580d5d8bc2cf773b78b372b2e2d1d0b4e6562f5aa539482fdb9f0f07a35fc8de430ff68f3cc8973765b51ae3f70a6af2c2ce2992c1343d4520a7f0f62152703a5a629157d799f7ada804bf4b93e74e5c4ecbb59ce98a47fac01999ffdf80e" 144 | }, 145 | { 146 | "key": "ff7d18abba0ab08c0f5871e3f1cdd6efbbbe25bf95569137a1d035092b0d6fd41c2ea249159ddd4881356a79f3ac79afaaae8d8e4269ab0c6787b3c0910133285230aa15ae03b6eafd1fe55984fc8b47", 147 | "salt": "d13bf79b94065012", 148 | "dkLen": 128, 149 | "c": 32, 150 | "r": 8, 151 | "N": 6, 152 | "p": 4, 153 | "dk": "d6fa6a9ae917814a17cb59fb7056ba55f0b509e6874c8692f7df88db5dd29dc4affd77cd92da8aa12f9854889f9268bc51188b066aa4257923af21fc38b99a3e2793c3dafe04341b8eb591072836a825b8358fb909efaeaaa23f14e1f8088e9d8f1e60d68dc509dd88662151a6eba276eeaa430eff3b39b51540f355e400435f" 154 | }, 155 | { 156 | "key": "55ee5f192117dc901575c3ffa89e2217b13dfafff2f44ee3fe72f1f0007902949d06f7f31d1527e46d36a3078ee134572aae2d675a7224acaf0b8bbdd9c1aaf452d6c079fc910f9c109cf90d9f6f70151e61900f478d15913e33bf08c749dbed7dbe0c3837937b54f66c3bd6c089fcec4d110724ef24214c3554b4fa552d519ca1249a155f4b4f9066f0211d97eee9cf4efd3184498677d5e5599e1864a57b9c", 157 | "salt": "00ea00c99ac56691", 158 | "dkLen": 128, 159 | "c": 32, 160 | "r": 8, 161 | "N": 6, 162 | "p": 4, 163 | "dk": "aa64060d5810b437d0f8f25478c93525db269000db468695d6e3f5a5d9c47051ed44514563e97948b06d70e79e7c0e9187f1226544f8b2615100508ee965dba067b1276fd781e007c196a1ba7932ef5951bb26cf2d1410bba58385100cdbcfe16af16c66f1e21f97aee5f595eda6c2602aa3fbd4a2894ca1c62f07a1eb821b4f" 164 | }, 165 | { 166 | "key": "ecb73fe425ada6288f2b", 167 | "salt": "aabd51b2f8771007", 168 | "dkLen": 128, 169 | "c": 32, 170 | "r": 16, 171 | "N": 4, 172 | "p": 4, 173 | "dk": "ba6c4f437c6fd16eceafe0da42a321cc2baeda584696d46ec853378094dfc0df250f1c12989a6813071a1ac2a521398cbe0061309c6dcad6d53b26266e6031173dbde1f6d114509934979a19d8be6c52cba689fcaff1320210238b48dad1a456484cf3d79feb783b85454cfadb879812f95456e55c127c950fab3f30d5b60b96" 174 | }, 175 | { 176 | "key": "50c68b678a8c1556f70ce8507bdf3576473f17d893de590c83148365a34ea67fdfe2897136d591a7", 177 | "salt": "949d4c56016bd2ca", 178 | "dkLen": 128, 179 | "c": 32, 180 | "r": 16, 181 | "N": 4, 182 | "p": 4, 183 | "dk": "14dce89d75fadeddf99f21c2efbc82fbf08245dde9409dd62eae66557b638c32214192cd276507c7cd935c2723b5804837e38adb791049928de25458c57a9ba3986a19c4e4735b8195ed8c4c91a7b183d226cb2e3bc32600736ded9f0ad43a83c64779a0733b223a4c4b852ddaac978344ea2f753c0d72ade3709ce2e634667d" 184 | }, 185 | { 186 | "key": "6fe5dc8f1ab19af5fb19fd6503c0f3c97abe917352040daa9e9c871d7171d1ad988a3358be79e54d38d5bef63d9e7032e5aa300405efcd603369c363da633605612cfe4139de0cd0a13c0a638d30832b", 187 | "salt": "9283d258217c2e08", 188 | "dkLen": 128, 189 | "c": 32, 190 | "r": 16, 191 | "N": 4, 192 | "p": 4, 193 | "dk": "920987a18be030c2c2bf4731e865f31e1949cd7983c88b1110e31a416fe8cb8643250a5c1842a59a81002bcdef31b6b3de97be0aaeb385336405ecd3a4ff7889e95e1e5d53276ff44ebf2554aae1f51562e0f0f80f0623f0398b6bfaba043caa9991fe289acd267fa6264b3ef085b10fbe8e3539d87ded304b01f85e228fb6c7" 194 | }, 195 | { 196 | "key": "4ff413a434de49d4682ba2b6cb8aacd4341831860804b1fe6c8af6f9aca7c5baa4703d602d60bac845cb5e2fa80b7b2bca1f8fa842da82c627393fa5305d5f407ce69e336e7863664ba6975671ebcaed917946a9b5dbeb115c8d4a879eac98e0881825471455a122f2569622cbfce7f17b27c70f130df8adf6f3a9c61da4971e035e6f6a22ee95bf7df4506fc2393a3713c6573b475d23d5a5e5e206bb29ee83", 197 | "salt": "d53462068dce0377", 198 | "dkLen": 128, 199 | "c": 32, 200 | "r": 16, 201 | "N": 4, 202 | "p": 4, 203 | "dk": "887a72b95f9c078f566c560fd431c280fcfa01b1908bfca9f32d86a7f741bf555371a39cc01dc0ef58c62594a14f3ac8da7ee10e58911baffa7c05dfd9308aad40206025888dd0f5f2e5d1780b18f74957861f483e72f743f307fa18444bf0cbe785daa9bd42c1adb812ac2c169304ffa2338da7244713760975e613f4dd6423" 204 | } 205 | ] 206 | } 207 | -------------------------------------------------------------------------------- /triplesec.go: -------------------------------------------------------------------------------- 1 | // The design and name of TripleSec is (C) Keybase 2013 2 | // This Go implementation is (C) Filippo Valsorda 2014 3 | // Use of this source code is governed by the MIT License 4 | 5 | // Package triplesec implements the TripleSec v3 and v4 encryption and authentication scheme. 6 | // 7 | // For details on TripleSec, go to https://keybase.io/triplesec/ 8 | package triplesec 9 | 10 | import ( 11 | "bytes" 12 | "crypto/aes" 13 | "crypto/cipher" 14 | "crypto/hmac" 15 | "crypto/rand" 16 | "crypto/sha512" 17 | "encoding/binary" 18 | "fmt" 19 | "hash" 20 | 21 | "golang.org/x/crypto/salsa20" 22 | "golang.org/x/crypto/scrypt" 23 | "golang.org/x/crypto/twofish" //nolint 24 | 25 | "github.com/keybase/go-crypto/sha3" 26 | ) 27 | 28 | type RandomnessGenerator interface { 29 | Read(b []byte) (n int, err error) 30 | } 31 | 32 | type CryptoRandGenerator struct{} 33 | 34 | func (crg CryptoRandGenerator) Read(b []byte) (n int, err error) { 35 | return rand.Read(b) 36 | } 37 | 38 | func NewCryptoRandGenerator() CryptoRandGenerator { 39 | return CryptoRandGenerator{} 40 | } 41 | 42 | var _ RandomnessGenerator = (*CryptoRandGenerator)(nil) 43 | 44 | type RandomTapeGenerator struct { 45 | randomTape *bytes.Reader 46 | } 47 | 48 | func NewRandomTapeGenerator(randomTape []byte) RandomTapeGenerator { 49 | return RandomTapeGenerator{bytes.NewReader(randomTape)} 50 | } 51 | 52 | func (rtg RandomTapeGenerator) Read(b []byte) (n int, err error) { 53 | return rtg.randomTape.Read(b) 54 | } 55 | 56 | var _ RandomnessGenerator = (*RandomTapeGenerator)(nil) 57 | 58 | const SaltLen = 16 59 | const VersionBytesLen = 4 60 | const AESIVLen = 16 61 | const TwofishIVLen = 16 62 | const SalsaIVLen = 24 63 | const MacOutputLen = 64 64 | const MacKeyLen = 48 65 | const CipherKeyLen = 32 66 | 67 | type Version uint32 68 | 69 | var LatestVersion Version = 4 70 | 71 | type VersionParams struct { 72 | MacKeyLen int 73 | TotalIVLen int 74 | TotalMacLen int 75 | TotalMacKeyLen int 76 | DkLen int 77 | UseTwofish bool 78 | UseKeccakOverSHA3 bool 79 | Version Version 80 | } 81 | 82 | var versionParamsLookup = map[Version]VersionParams{ 83 | 3: { 84 | TotalIVLen: AESIVLen + TwofishIVLen + SalsaIVLen, 85 | TotalMacLen: 2 * MacOutputLen, 86 | TotalMacKeyLen: 2 * MacKeyLen, 87 | DkLen: 2*MacKeyLen + 3*CipherKeyLen, 88 | UseTwofish: true, 89 | UseKeccakOverSHA3: true, 90 | Version: 3, 91 | }, 92 | 4: { 93 | TotalIVLen: AESIVLen + SalsaIVLen, 94 | TotalMacLen: 2 * MacOutputLen, 95 | TotalMacKeyLen: 2 * MacKeyLen, 96 | DkLen: 2*MacKeyLen + 2*CipherKeyLen, 97 | UseTwofish: false, 98 | UseKeccakOverSHA3: false, 99 | Version: 4, 100 | }, 101 | } 102 | 103 | func (vp *VersionParams) Overhead() int { 104 | return len(MagicBytes) + VersionBytesLen + SaltLen + vp.TotalMacLen + vp.TotalIVLen 105 | } 106 | 107 | type Cipher struct { 108 | passphrase []byte 109 | salt []byte 110 | derivedKey []byte 111 | versionParams VersionParams 112 | rng RandomnessGenerator 113 | } 114 | 115 | func scrub(b []byte) { 116 | for i := range b { 117 | b[i] = 0 118 | } 119 | } 120 | 121 | // NewCipher makes an instance of TripleSec using a particular key and 122 | // a particular salt 123 | func NewCipher(passphrase []byte, salt []byte, version Version) (*Cipher, error) { 124 | return NewCipherWithRng(passphrase, salt, version, NewCryptoRandGenerator()) 125 | } 126 | 127 | // NewCipherWithRng makes an instance of TripleSec using a particular key and 128 | // a particular salt and uses a given randomness stream 129 | func NewCipherWithRng(passphrase []byte, salt []byte, version Version, rng RandomnessGenerator) (*Cipher, error) { 130 | if salt != nil && len(salt) != SaltLen { 131 | return nil, fmt.Errorf("Need a salt of size %d", SaltLen) 132 | } 133 | var versionParams VersionParams 134 | var ok bool 135 | if versionParams, ok = versionParamsLookup[version]; !ok { 136 | return nil, fmt.Errorf("Not a valid version") 137 | } 138 | return &Cipher{passphrase, salt, nil, versionParams, rng}, nil 139 | } 140 | 141 | func (c *Cipher) Scrub() { 142 | scrub(c.passphrase) 143 | scrub(c.derivedKey) 144 | } 145 | 146 | func (c *Cipher) SetSalt(salt []byte) error { 147 | if len(salt) < SaltLen { 148 | return fmt.Errorf("need salt of at least %d bytes", SaltLen) 149 | } 150 | c.salt = salt[0:SaltLen] 151 | return nil 152 | } 153 | 154 | func (c *Cipher) GetSalt() ([]byte, error) { 155 | if c.salt != nil { 156 | return c.salt, nil 157 | } 158 | c.salt = make([]byte, SaltLen) 159 | _, err := c.rng.Read(c.salt) 160 | if err != nil { 161 | return nil, err 162 | } 163 | return c.salt, nil 164 | } 165 | 166 | func (c *Cipher) DeriveKey(extra int) ([]byte, []byte, error) { 167 | 168 | dkLen := c.versionParams.DkLen + extra 169 | 170 | if c.derivedKey == nil || len(c.derivedKey) < dkLen { 171 | dk, err := scrypt.Key(c.passphrase, c.salt, 32768, 8, 1, dkLen) 172 | if err != nil { 173 | return nil, nil, err 174 | } 175 | c.derivedKey = dk 176 | } 177 | return c.derivedKey[0:c.versionParams.DkLen], c.derivedKey[c.versionParams.DkLen:], nil 178 | } 179 | 180 | // MagicBytes are the four bytes prefixed to every TripleSec 181 | // ciphertext, 1c 94 d7 de. 182 | var MagicBytes = [4]byte{0x1c, 0x94, 0xd7, 0xde} 183 | 184 | // Encrypt encrypts and signs a plaintext message with TripleSec using a random 185 | // salt and the Cipher passphrase. The dst buffer size must be at least len(src) 186 | // + Overhead. dst and src can not overlap. src is left untouched. 187 | // 188 | // Encrypt returns a error on memory or RNG failures. 189 | func (c *Cipher) Encrypt(src []byte) (dst []byte, err error) { 190 | if len(src) < 1 { 191 | return nil, fmt.Errorf("the plaintext cannot be empty") 192 | } 193 | 194 | dst = make([]byte, len(src)+c.versionParams.Overhead()) 195 | buf := bytes.NewBuffer(dst[:0]) 196 | 197 | _, err = buf.Write(MagicBytes[0:]) 198 | if err != nil { 199 | return 200 | } 201 | 202 | // Write version 203 | err = binary.Write(buf, binary.BigEndian, c.versionParams.Version) 204 | if err != nil { 205 | return 206 | } 207 | 208 | salt, err := c.GetSalt() 209 | if err != nil { 210 | return 211 | } 212 | 213 | _, err = buf.Write(salt) 214 | if err != nil { 215 | return 216 | } 217 | 218 | dk, _, err := c.DeriveKey(0) 219 | if err != nil { 220 | return 221 | } 222 | macKeys := dk[:c.versionParams.TotalMacKeyLen] 223 | cipherKeys := dk[c.versionParams.TotalMacKeyLen:] 224 | 225 | // The allocation over here can be made better 226 | encryptedData, err := encryptData(src, cipherKeys, c.rng, c.versionParams) 227 | if err != nil { 228 | return 229 | } 230 | 231 | authenticatedData := make([]byte, 0, buf.Len()+len(encryptedData)) 232 | authenticatedData = append(authenticatedData, buf.Bytes()...) 233 | authenticatedData = append(authenticatedData, encryptedData...) 234 | macsOutput := generateMACs(authenticatedData, macKeys, c.versionParams) 235 | 236 | _, err = buf.Write(macsOutput) 237 | if err != nil { 238 | return 239 | } 240 | _, err = buf.Write(encryptedData) 241 | if err != nil { 242 | return 243 | } 244 | 245 | if buf.Len() != len(src)+c.versionParams.Overhead() { 246 | err = fmt.Errorf("something went terribly wrong: output size wrong") 247 | return 248 | } 249 | 250 | return buf.Bytes(), nil 251 | } 252 | 253 | func encryptData(plain, keys []byte, rng RandomnessGenerator, versionParams VersionParams) ([]byte, error) { 254 | var iv, key []byte 255 | var block cipher.Block 256 | var stream cipher.Stream 257 | 258 | ivOffset := versionParams.TotalIVLen 259 | res := make([]byte, len(plain)+ivOffset) 260 | 261 | // Generate IVs 262 | iv = res[:ivOffset] 263 | _, err := rng.Read(iv) 264 | if err != nil { 265 | return nil, err 266 | } 267 | offset := 0 268 | aesIV := iv[offset : offset+AESIVLen] 269 | offset += AESIVLen 270 | var twofishIV []byte 271 | if versionParams.UseTwofish { 272 | twofishIV = iv[offset : offset+TwofishIVLen] 273 | offset += TwofishIVLen 274 | } 275 | salsaIV := iv[offset : offset+SalsaIVLen] 276 | 277 | cipherOffset := 0 278 | 279 | // Salsa20 280 | // For some reason salsa20 API is different 281 | keyArray := new([32]byte) 282 | copy(keyArray[:], keys[len(keys)-cipherOffset-CipherKeyLen:]) 283 | cipherOffset += CipherKeyLen 284 | salsa20.XORKeyStream(res[ivOffset:], plain, salsaIV, keyArray) 285 | ivOffset -= len(salsaIV) 286 | 287 | // Twofish 288 | if versionParams.UseTwofish { 289 | key = keys[len(keys)-cipherOffset-CipherKeyLen : len(keys)-cipherOffset] 290 | cipherOffset += CipherKeyLen 291 | block, err = twofish.NewCipher(key) 292 | if err != nil { 293 | return nil, err 294 | } 295 | stream = cipher.NewCTR(block, twofishIV) 296 | stream.XORKeyStream(res[ivOffset:], res[ivOffset:]) 297 | ivOffset -= len(twofishIV) 298 | } 299 | 300 | // AES 301 | key = keys[len(keys)-cipherOffset-CipherKeyLen : len(keys)-cipherOffset] 302 | block, err = aes.NewCipher(key) 303 | if err != nil { 304 | return nil, err 305 | } 306 | stream = cipher.NewCTR(block, aesIV) 307 | stream.XORKeyStream(res[ivOffset:], res[ivOffset:]) 308 | ivOffset -= len(aesIV) 309 | 310 | if ivOffset != 0 { 311 | return nil, CorruptionError{"something went terribly wrong during encryption: ivOffset final value non-zero"} 312 | } 313 | 314 | return res, nil 315 | } 316 | 317 | func generateMACs(data, keys []byte, versionParams VersionParams) []byte { 318 | res := make([]byte, 0, 64*2) 319 | 320 | key := keys[:MacKeyLen] 321 | mac := hmac.New(sha512.New, key) 322 | _, _ = mac.Write(data) 323 | res = mac.Sum(res) 324 | 325 | key = keys[MacKeyLen:] 326 | var digestmodFn func() hash.Hash 327 | if versionParams.UseKeccakOverSHA3 { 328 | digestmodFn = sha3.NewLegacyKeccak512 329 | } else { 330 | digestmodFn = sha3.New512 331 | } 332 | mac = hmac.New(digestmodFn, key) 333 | _, _ = mac.Write(data) 334 | res = mac.Sum(res) 335 | 336 | return res 337 | } 338 | 339 | // Decrypt decrypts a TripleSec ciphertext using the Cipher passphrase. 340 | // The dst buffer size must be at least len(src) - Overhead. 341 | // dst and src can not overlap. src is left untouched. 342 | // 343 | // Encrypt returns a error if the ciphertext is not recognized, if 344 | // authentication fails or on memory failures. 345 | func (c *Cipher) Decrypt(src []byte) (res []byte, err error) { 346 | if len(src) < len(MagicBytes)+VersionBytesLen { 347 | err = CorruptionError{"decryption underrun"} 348 | return 349 | } 350 | 351 | if !bytes.Equal(src[:len(MagicBytes)], MagicBytes[0:]) { 352 | err = CorruptionError{"wrong magic bytes"} 353 | return 354 | } 355 | 356 | vB := bytes.NewBuffer(src[len(MagicBytes) : len(MagicBytes)+VersionBytesLen]) 357 | var version Version 358 | err = binary.Read(vB, binary.BigEndian, &version) 359 | if err != nil { 360 | err = CorruptionError{err.Error()} 361 | return 362 | } 363 | 364 | versionParams, ok := versionParamsLookup[version] 365 | if !ok { 366 | return nil, VersionError{version} 367 | } 368 | 369 | err = c.SetSalt(src[8:24]) 370 | if err != nil { 371 | return 372 | } 373 | 374 | dk, _, err := c.DeriveKey(0) 375 | if err != nil { 376 | return 377 | } 378 | macKeys := dk[:c.versionParams.TotalMacKeyLen] 379 | cipherKeys := dk[c.versionParams.TotalMacKeyLen:] 380 | 381 | macs := src[24 : 24+64*2] 382 | encryptedData := src[24+64*2:] 383 | 384 | authenticatedData := make([]byte, 0, 24+len(encryptedData)) 385 | authenticatedData = append(authenticatedData, src[:24]...) 386 | authenticatedData = append(authenticatedData, encryptedData...) 387 | 388 | if !hmac.Equal(macs, generateMACs(authenticatedData, macKeys, versionParams)) { 389 | err = BadPassphraseError{} 390 | return 391 | } 392 | 393 | dst := make([]byte, len(src)-versionParams.Overhead()) 394 | 395 | err = decryptData(dst, encryptedData, cipherKeys, versionParams) 396 | if err != nil { 397 | return 398 | } 399 | 400 | return dst, nil 401 | } 402 | 403 | func decryptData(dst, data, keys []byte, versionParams VersionParams) error { 404 | var iv, key []byte 405 | var block cipher.Block 406 | var stream cipher.Stream 407 | var err error 408 | 409 | buffer := append([]byte{}, data...) 410 | 411 | ivOffset := 0 412 | cipherOffset := 0 413 | 414 | ivOffset += AESIVLen 415 | iv = buffer[:ivOffset] 416 | key = keys[cipherOffset : cipherOffset+CipherKeyLen] 417 | cipherOffset += CipherKeyLen 418 | block, err = aes.NewCipher(key) 419 | if err != nil { 420 | return err 421 | } 422 | stream = cipher.NewCTR(block, iv) 423 | stream.XORKeyStream(buffer[ivOffset:], buffer[ivOffset:]) 424 | 425 | if versionParams.UseTwofish { 426 | ivOffset += TwofishIVLen 427 | iv = buffer[ivOffset-TwofishIVLen : ivOffset] 428 | key = keys[cipherOffset : cipherOffset+CipherKeyLen] 429 | cipherOffset += CipherKeyLen 430 | block, err = twofish.NewCipher(key) 431 | if err != nil { 432 | return err 433 | } 434 | stream = cipher.NewCTR(block, iv) 435 | stream.XORKeyStream(buffer[ivOffset:], buffer[ivOffset:]) 436 | } 437 | 438 | ivOffset += SalsaIVLen 439 | iv = buffer[ivOffset-SalsaIVLen : ivOffset] 440 | keyArray := new([32]byte) 441 | copy(keyArray[:], keys[cipherOffset:cipherOffset+CipherKeyLen]) 442 | salsa20.XORKeyStream(dst, buffer[ivOffset:], iv, keyArray) 443 | 444 | if len(buffer[ivOffset:]) != len(data)-versionParams.TotalIVLen { 445 | return CorruptionError{"something went terribly wrong during decryption: buffer size is wrong"} 446 | } 447 | 448 | return nil 449 | } 450 | -------------------------------------------------------------------------------- /triplesec_test.go: -------------------------------------------------------------------------------- 1 | // The design and name of TripleSec is (C) Keybase 2013 2 | // This Go implementation is (C) Filippo Valsorda 2014 3 | // Use of this source code is governed by the MIT License 4 | 5 | package triplesec 6 | 7 | import ( 8 | "bytes" 9 | "encoding/hex" 10 | "encoding/json" 11 | "fmt" 12 | "os" 13 | "testing" 14 | 15 | "github.com/stretchr/testify/require" 16 | ) 17 | 18 | func testCycle(t *testing.T, version Version) { 19 | plaintext := []byte("1234567890-") 20 | password := []byte("42") 21 | 22 | c, err := NewCipher(password, nil, version) 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | 27 | origPlaintext := append([]byte{}, plaintext...) 28 | ciphertext, err := c.Encrypt(plaintext) 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | 33 | origCiphertext := append([]byte{}, ciphertext...) 34 | newPlaintext, err := c.Decrypt(ciphertext) 35 | if err != nil { 36 | t.Fatal(err) 37 | } 38 | 39 | if !bytes.Equal(newPlaintext, plaintext) { 40 | t.Error("newPlaintext != plaintext") 41 | } 42 | if !bytes.Equal(origPlaintext, plaintext) { 43 | t.Error("origPlaintext != plaintext") 44 | } 45 | if !bytes.Equal(origCiphertext, ciphertext) { 46 | t.Error("origCiphertext != ciphertext") 47 | } 48 | if !bytes.Equal(password, []byte("42")) { 49 | t.Error("password changed") 50 | } 51 | } 52 | 53 | func TestCycle(t *testing.T) { 54 | for version := range versionParamsLookup { 55 | testCycle(t, version) 56 | } 57 | } 58 | 59 | func BenchmarkEncrypt(b *testing.B) { 60 | plaintext := []byte("1234567890-") 61 | password := []byte("42") 62 | 63 | c, err := NewCipher(password, nil, Version(3)) 64 | if err != nil { 65 | b.Fatal(err) 66 | } 67 | 68 | for i := 0; i < b.N; i++ { 69 | _, err := c.Encrypt(plaintext) 70 | if err != nil { 71 | b.Fatal(err) 72 | } 73 | } 74 | } 75 | 76 | func BenchmarkDecrypt(b *testing.B) { 77 | plaintext := []byte("1234567890-") 78 | password := []byte("42") 79 | 80 | c, err := NewCipher(password, nil, Version(3)) 81 | if err != nil { 82 | b.Fatal(err) 83 | } 84 | ciphertext, err := c.Encrypt(plaintext) 85 | if err != nil { 86 | b.Fatal(err) 87 | } 88 | 89 | b.ResetTimer() 90 | 91 | for i := 0; i < b.N; i++ { 92 | _, err = c.Decrypt(ciphertext) 93 | if err != nil { 94 | b.Fatal(err) 95 | } 96 | } 97 | } 98 | 99 | func testBiggerBufSizes(t *testing.T, version Version) { 100 | // TODO: should we resize the buffers when we are passed smaller ones? 101 | 102 | plaintext := []byte("1234567890-") 103 | password := []byte("42") 104 | 105 | c, err := NewCipher(password, nil, version) 106 | if err != nil { 107 | t.Fatal(err) 108 | } 109 | 110 | origPlaintext := append([]byte{}, plaintext...) 111 | ciphertext, err := c.Encrypt(plaintext) 112 | if err != nil { 113 | t.Fatal(err) 114 | } 115 | 116 | origCiphertext := append([]byte{}, ciphertext...) 117 | newPlaintext, err := c.Decrypt(ciphertext) 118 | if err != nil { 119 | t.Fatal(err) 120 | } 121 | 122 | if !bytes.Equal(newPlaintext[:len(plaintext)], plaintext) { 123 | t.Error("newPlaintext != plaintext") 124 | } 125 | if !bytes.Equal(origPlaintext, plaintext) { 126 | t.Error("origPlaintext != plaintext") 127 | } 128 | if !bytes.Equal(origCiphertext, ciphertext) { 129 | t.Error("origCiphertext != ciphertext") 130 | } 131 | if !bytes.Equal(password, []byte("42")) { 132 | t.Error("password changed") 133 | } 134 | } 135 | 136 | func TestBiggerBufSizes(t *testing.T) { 137 | for version := range versionParamsLookup { 138 | testBiggerBufSizes(t, version) 139 | } 140 | } 141 | 142 | func testSmallerBufSizes(t *testing.T, version Version) { 143 | plaintext := []byte("1234567890-") 144 | password := []byte("42") 145 | 146 | c, err := NewCipher(password, nil, version) 147 | if err != nil { 148 | t.Fatal(err) 149 | } 150 | 151 | origPlaintext := append([]byte{}, plaintext...) 152 | ciphertext, err := c.Encrypt(plaintext) 153 | if err != nil { 154 | t.Fatal(err) 155 | } 156 | 157 | origCiphertext := append([]byte{}, ciphertext...) 158 | newPlaintext, err := c.Decrypt(ciphertext) 159 | if err != nil { 160 | t.Fatal(err) 161 | } 162 | 163 | if !bytes.Equal(newPlaintext, plaintext) { 164 | t.Error("newPlaintext != plaintext") 165 | } 166 | if !bytes.Equal(origPlaintext, plaintext) { 167 | t.Error("origPlaintext != plaintext") 168 | } 169 | if !bytes.Equal(origCiphertext, ciphertext) { 170 | t.Error("origCiphertext != ciphertext") 171 | } 172 | if !bytes.Equal(password, []byte("42")) { 173 | t.Error("password changed") 174 | } 175 | } 176 | 177 | func TestSmallerBufSizes(t *testing.T) { 178 | for version := range versionParamsLookup { 179 | testSmallerBufSizes(t, version) 180 | } 181 | } 182 | 183 | func TestVectorV3(t *testing.T) { 184 | ciphertext, _ := hex.DecodeString("1c94d7de0000000359a5e5d60f09ebb6bc3fdab6642725e03bc3d51e167fa60327df567476d467f8b6ce65a909b4f582443f230ff10a36f60315ebce1cf1395d7b763c768764207f4f4cc5207a21272f3a5542f35db73c94fbc7bd551d4d6b0733e0b27fdf9606b8a26d45c4b79818791b6ae1ad34c23e58de482d454895618a1528ec722c5218650f8a2f55f63a6066ccf875f46c9b68ed31bc1ddce8881d704be597e1b5006d16ebe091a02e24d569f3d09b0578d12f955543e1a1f1dd75784b8b4cba7ca0bb7044389eb6354cea628a21538d") 185 | c, err := NewCipher([]byte("42"), nil, Version(3)) 186 | if err != nil { 187 | t.Error(err) 188 | } 189 | buf, err := c.Decrypt(ciphertext) 190 | if err != nil { 191 | t.Error(err) 192 | } 193 | if !bytes.Equal(buf, []byte("ciao")) { 194 | t.Errorf("no equal at end %v", buf) 195 | } 196 | } 197 | 198 | func TestBadPwV3(t *testing.T) { 199 | ciphertext, _ := hex.DecodeString("1c94d7de0000000359a5e5d60f09ebb6bc3fdab6642725e03bc3d51e167fa60327df567476d467f8b6ce65a909b4f582443f230ff10a36f60315ebce1cf1395d7b763c768764207f4f4cc5207a21272f3a5542f35db73c94fbc7bd551d4d6b0733e0b27fdf9606b8a26d45c4b79818791b6ae1ad34c23e58de482d454895618a1528ec722c5218650f8a2f55f63a6066ccf875f46c9b68ed31bc1ddce8881d704be597e1b5006d16ebe091a02e24d569f3d09b0578d12f955543e1a1f1dd75784b8b4cba7ca0bb7044389eb6354cea628a21538d") 200 | c, _ := NewCipher([]byte("423"), nil, Version(3)) 201 | _, err := c.Decrypt(ciphertext) 202 | if err == nil { 203 | t.Error("needed an error on bad PW") 204 | } else if _, ok := err.(BadPassphraseError); !ok { 205 | t.Error("got wrong type of error") 206 | } 207 | } 208 | 209 | func TestVectorV4(t *testing.T) { 210 | ciphertext, _ := hex.DecodeString("1c94d7de00000004ab62712b6a43fba017a7a13333b59d3650365fcebded3bd64741a99b2070fa12e4145766afa1b2dbcaca4d2053963f441be82963046766f16a4f82186a9ba7a7cf04f19da9a695a4a7ae9f6036a5d3b456ad97d512af55e61245c9a096db8a4b73cc64491ec67e5381ec14f2ce6f3db922b5cec7cea86305681a0204d6fb9522e7ec8851f8d85c4e4319473c2899ece487324093f144d27ea13355fd9a03a0765afc5f5750152824c6632dfd50bd25ac340aaa6e6cd3664c21d4501ef8b3107c3fa62b9a97d79a9ccc64") 211 | key, _ := hex.DecodeString("f6b305811712d06e8723") 212 | c, err := NewCipher(key, nil, Version(4)) 213 | if err != nil { 214 | t.Error(err) 215 | } 216 | buf, err := c.Decrypt(ciphertext) 217 | if err != nil { 218 | t.Error(err) 219 | } 220 | exp := []byte("Hello! I am ASCII!") 221 | if !bytes.Equal(buf, exp) { 222 | t.Errorf("no equal at end exp=%s, got=%s", string(exp), string(buf)) 223 | } 224 | } 225 | 226 | func TestBadPwV4(t *testing.T) { 227 | ciphertext, _ := hex.DecodeString("1c94d7de00000004ab62712b6a43fba017a7a13333b59d3650365fcebded3bd64741a99b2070fa12e4145766afa1b2dbcaca4d2053963f441be82963046766f16a4f82186a9ba7a7cf04f19da9a695a4a7ae9f6036a5d3b456ad97d512af55e61245c9a096db8a4b73cc64491ec67e5381ec14f2ce6f3db922b5cec7cea86305681a0204d6fb9522e7ec8851f8d85c4e4319473c2899ece487324093f144d27ea13355fd9a03a0765afc5f5750152824c6632dfd50bd25ac340aaa6e6cd3664c21d4501ef8b3107c3fa62b9a97d79a9ccc64") 228 | c, _ := NewCipher([]byte("wrong password"), nil, Version(4)) 229 | _, err := c.Decrypt(ciphertext) 230 | if err == nil { 231 | t.Error("needed an error on bad PW") 232 | } else if _, ok := err.(BadPassphraseError); !ok { 233 | t.Error("got wrong type of error") 234 | } 235 | } 236 | 237 | type vector struct { 238 | Key string `json:"key"` 239 | Pt string `json:"pt"` 240 | Ct string `json:"ct"` 241 | R string `json:"r"` 242 | } 243 | 244 | type testVectors struct { 245 | Vectors []vector `json:"vectors"` 246 | } 247 | 248 | func TestSpec(t *testing.T) { 249 | for _, version := range []Version{3, 4} { 250 | handle, _ := os.Open(fmt.Sprintf("spec/triplesec_v%d.json", version)) 251 | defer handle.Close() 252 | 253 | var vs testVectors 254 | dec := json.NewDecoder(handle) 255 | err := dec.Decode(&vs) 256 | require.NoError(t, err) 257 | 258 | for _, v := range vs.Vectors { 259 | key, _ := hex.DecodeString(v.Key) 260 | pt, _ := hex.DecodeString(v.Pt) 261 | ct, _ := hex.DecodeString(v.Ct) 262 | r, _ := hex.DecodeString(v.R) 263 | 264 | cipher, _ := NewCipher(key, nil, version) 265 | decrypted, _ := cipher.Decrypt(ct) 266 | if v.Pt != hex.EncodeToString(decrypted) { 267 | t.Errorf("failed decryption test vector for version %v and key %v", version, key) 268 | } 269 | 270 | fixedRandomnessCipher, _ := NewCipherWithRng(key, nil, version, NewRandomTapeGenerator(r)) 271 | encrypted, _ := fixedRandomnessCipher.Encrypt(pt) 272 | if v.Ct != hex.EncodeToString(encrypted) { 273 | t.Errorf("failed encryption test vector for version %x and key %x", version, key) 274 | } 275 | } 276 | } 277 | } 278 | 279 | func TestRandomness(t *testing.T) { 280 | for _, version := range []Version{3, 4} { 281 | key := []byte("YELLOW_SUBMARINE") 282 | cipher, _ := NewCipher(key, nil, version) 283 | pt := []byte("foobar") 284 | once, _ := cipher.Encrypt(pt) 285 | twice, _ := cipher.Encrypt(pt) 286 | onceHex := hex.EncodeToString(once) 287 | twiceHex := hex.EncodeToString(twice) 288 | if onceHex == twiceHex { 289 | t.Errorf("got same encryption twice in a row") 290 | } 291 | cipher, _ = NewCipher(key, nil, version) 292 | thrice, _ := cipher.Encrypt(pt) 293 | thriceHex := hex.EncodeToString(thrice) 294 | if onceHex == thriceHex || twiceHex == thriceHex { 295 | t.Errorf("got same encryption twice after making cipher again") 296 | } 297 | } 298 | } 299 | --------------------------------------------------------------------------------