Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

srp

Package Overview
Dependencies
Maintainers
3
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

srp - npm Package Compare versions

Comparing version 0.0.4 to 0.2.0

rfc2945.txt

1

index.js
module.exports = require('./lib/srp');
module.exports.params = require('./lib/params');

@@ -14,146 +14,167 @@ /*

const bigint = require('bigint');
// since these are meant to be used internally, all values are numbers. If
// you want to add parameter sets, you'll need to convert them to bignums.
const bignum = require('bignum');
function hex(s) {
return bignum(s.split(/\s/).join(''), 16);
}
module.exports = {
1024: {
N: bigint('EEAF0AB9 ADB38DD6 9C33F80A FA8FC5E8 60726187 75FF3C0B 9EA2314C'
+'9C256576 D674DF74 96EA81D3 383B4813 D692C6E0 E0D5D8E2 50B98BE4'
+'8E495C1D 6089DAD1 5DC7D7B4 6154D6B6 CE8EF4AD 69B15D49 82559B29'
+'7BCF1885 C529F566 660E57EC 68EDBC3C 05726CC0 2FD4CBF4 976EAA9A'
+'FD5138FE 8376435B 9FC61D2F C0EB06E3', 16),
g: bigint(2)},
N_length_bits: 1024,
N: hex(' EEAF0AB9 ADB38DD6 9C33F80A FA8FC5E8 60726187 75FF3C0B 9EA2314C'
+'9C256576 D674DF74 96EA81D3 383B4813 D692C6E0 E0D5D8E2 50B98BE4'
+'8E495C1D 6089DAD1 5DC7D7B4 6154D6B6 CE8EF4AD 69B15D49 82559B29'
+'7BCF1885 C529F566 660E57EC 68EDBC3C 05726CC0 2FD4CBF4 976EAA9A'
+'FD5138FE 8376435B 9FC61D2F C0EB06E3'),
g: hex('02'),
hash: 'sha1'},
1536: {
N: bigint('9DEF3CAF B939277A B1F12A86 17A47BBB DBA51DF4 99AC4C80 BEEEA961'
+'4B19CC4D 5F4F5F55 6E27CBDE 51C6A94B E4607A29 1558903B A0D0F843'
+'80B655BB 9A22E8DC DF028A7C EC67F0D0 8134B1C8 B9798914 9B609E0B'
+'E3BAB63D 47548381 DBC5B1FC 764E3F4B 53DD9DA1 158BFD3E 2B9C8CF5'
+'6EDF0195 39349627 DB2FD53D 24B7C486 65772E43 7D6C7F8C E442734A'
+'F7CCB7AE 837C264A E3A9BEB8 7F8A2FE9 B8B5292E 5A021FFF 5E91479E'
+'8CE7A28C 2442C6F3 15180F93 499A234D CF76E3FE D135F9BB', 16),
g: bigint(2)},
N_length_bits: 1536,
N: hex(' 9DEF3CAF B939277A B1F12A86 17A47BBB DBA51DF4 99AC4C80 BEEEA961'
+'4B19CC4D 5F4F5F55 6E27CBDE 51C6A94B E4607A29 1558903B A0D0F843'
+'80B655BB 9A22E8DC DF028A7C EC67F0D0 8134B1C8 B9798914 9B609E0B'
+'E3BAB63D 47548381 DBC5B1FC 764E3F4B 53DD9DA1 158BFD3E 2B9C8CF5'
+'6EDF0195 39349627 DB2FD53D 24B7C486 65772E43 7D6C7F8C E442734A'
+'F7CCB7AE 837C264A E3A9BEB8 7F8A2FE9 B8B5292E 5A021FFF 5E91479E'
+'8CE7A28C 2442C6F3 15180F93 499A234D CF76E3FE D135F9BB'),
g: hex('02'),
hash: 'sha1'},
2048: {
N: bigint('AC6BDB41 324A9A9B F166DE5E 1389582F AF72B665 1987EE07 FC319294'
+'3DB56050 A37329CB B4A099ED 8193E075 7767A13D D52312AB 4B03310D'
+'CD7F48A9 DA04FD50 E8083969 EDB767B0 CF609517 9A163AB3 661A05FB'
+'D5FAAAE8 2918A996 2F0B93B8 55F97993 EC975EEA A80D740A DBF4FF74'
+'7359D041 D5C33EA7 1D281E44 6B14773B CA97B43A 23FB8016 76BD207A'
+'436C6481 F1D2B907 8717461A 5B9D32E6 88F87748 544523B5 24B0D57D'
+'5EA77A27 75D2ECFA 032CFBDB F52FB378 61602790 04E57AE6 AF874E73'
+'03CE5329 9CCC041C 7BC308D8 2A5698F3 A8D0C382 71AE35F8 E9DBFBB6'
+'94B5C803 D89F7AE4 35DE236D 525F5475 9B65E372 FCD68EF2 0FA7111F'
+'9E4AFF73', 16),
g: bigint(2)},
N_length_bits: 2048,
N: hex(' AC6BDB41 324A9A9B F166DE5E 1389582F AF72B665 1987EE07 FC319294'
+'3DB56050 A37329CB B4A099ED 8193E075 7767A13D D52312AB 4B03310D'
+'CD7F48A9 DA04FD50 E8083969 EDB767B0 CF609517 9A163AB3 661A05FB'
+'D5FAAAE8 2918A996 2F0B93B8 55F97993 EC975EEA A80D740A DBF4FF74'
+'7359D041 D5C33EA7 1D281E44 6B14773B CA97B43A 23FB8016 76BD207A'
+'436C6481 F1D2B907 8717461A 5B9D32E6 88F87748 544523B5 24B0D57D'
+'5EA77A27 75D2ECFA 032CFBDB F52FB378 61602790 04E57AE6 AF874E73'
+'03CE5329 9CCC041C 7BC308D8 2A5698F3 A8D0C382 71AE35F8 E9DBFBB6'
+'94B5C803 D89F7AE4 35DE236D 525F5475 9B65E372 FCD68EF2 0FA7111F'
+'9E4AFF73'),
g: hex('02'),
hash: 'sha256'},
3072: {
N: bigint('FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08'
+'8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B'
+'302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9'
+'A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6'
+'49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8'
+'FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D'
+'670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C'
+'180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718'
+'3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D'
+'04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D'
+'B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226'
+'1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C'
+'BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC'
+'E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF', 16),
g: bigint(5)},
N_length_bits: 3072,
N: hex(' FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08'
+'8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B'
+'302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9'
+'A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6'
+'49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8'
+'FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D'
+'670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C'
+'180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718'
+'3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D'
+'04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D'
+'B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226'
+'1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C'
+'BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC'
+'E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF'),
g: hex('05'),
hash: 'sha256'},
4096: {
N: bigint('FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08'
+'8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B'
+'302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9'
+'A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6'
+'49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8'
+'FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D'
+'670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C'
+'180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718'
+'3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D'
+'04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D'
+'B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226'
+'1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C'
+'BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC'
+'E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26'
+'99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB'
+'04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2'
+'233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127'
+'D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199'
+'FFFFFFFF FFFFFFFF', 16),
g: bigint(5)},
N_length_bits: 4096,
N: hex(' FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08'
+'8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B'
+'302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9'
+'A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6'
+'49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8'
+'FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D'
+'670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C'
+'180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718'
+'3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D'
+'04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D'
+'B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226'
+'1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C'
+'BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC'
+'E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26'
+'99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB'
+'04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2'
+'233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127'
+'D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199'
+'FFFFFFFF FFFFFFFF'),
g: hex('05'),
hash: 'sha256'},
6244: {
N: bigint('FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08'
+'8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B'
+'302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9'
+'A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6'
+'49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8'
+'FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D'
+'670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C'
+'180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718'
+'3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D'
+'04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D'
+'B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226'
+'1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C'
+'BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC'
+'E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26'
+'99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB'
+'04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2'
+'233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127'
+'D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492'
+'36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406'
+'AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918'
+'DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151'
+'2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03'
+'F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F'
+'BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA'
+'CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B'
+'B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632'
+'387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E'
+'6DCC4024 FFFFFFFF FFFFFFFF', 16),
g: bigint(5)},
N_length_bits: 6244,
N: hex(' FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08'
+'8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B'
+'302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9'
+'A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6'
+'49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8'
+'FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D'
+'670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C'
+'180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718'
+'3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D'
+'04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D'
+'B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226'
+'1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C'
+'BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC'
+'E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26'
+'99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB'
+'04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2'
+'233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127'
+'D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492'
+'36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406'
+'AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918'
+'DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151'
+'2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03'
+'F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F'
+'BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA'
+'CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B'
+'B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632'
+'387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E'
+'6DCC4024 FFFFFFFF FFFFFFFF'),
g: hex('05'),
hash: 'sha256'},
8192: {
N: bigint('FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08'
+'8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B'
+'302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9'
+'A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6'
+'49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8'
+'FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D'
+'670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C'
+'180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718'
+'3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D'
+'04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D'
+'B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226'
+'1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C'
+'BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC'
+'E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26'
+'99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB'
+'04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2'
+'233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127'
+'D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492'
+'36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406'
+'AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918'
+'DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151'
+'2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03'
+'F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F'
+'BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA'
+'CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B'
+'B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632'
+'387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E'
+'6DBE1159 74A3926F 12FEE5E4 38777CB6 A932DF8C D8BEC4D0 73B931BA'
+'3BC832B6 8D9DD300 741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C'
+'5AE4F568 3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9'
+'22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B 4BCBC886'
+'2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A 062B3CF5 B3A278A6'
+'6D2A13F8 3F44F82D DF310EE0 74AB6A36 4597E899 A0255DC1 64F31CC5'
+'0846851D F9AB4819 5DED7EA1 B1D510BD 7EE74D73 FAF36BC3 1ECFA268'
+'359046F4 EB879F92 4009438B 481C6CD7 889A002E D5EE382B C9190DA6'
+'FC026E47 9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71'
+'60C980DD 98EDD3DF FFFFFFFF FFFFFFFF', 16),
g: bigint(19)}
N_length_bits: 8192,
N: hex(' FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08'
+'8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B'
+'302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9'
+'A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6'
+'49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8'
+'FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D'
+'670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C'
+'180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718'
+'3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D'
+'04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D'
+'B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226'
+'1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C'
+'BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC'
+'E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26'
+'99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB'
+'04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2'
+'233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127'
+'D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492'
+'36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406'
+'AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918'
+'DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151'
+'2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03'
+'F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F'
+'BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA'
+'CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B'
+'B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632'
+'387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E'
+'6DBE1159 74A3926F 12FEE5E4 38777CB6 A932DF8C D8BEC4D0 73B931BA'
+'3BC832B6 8D9DD300 741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C'
+'5AE4F568 3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9'
+'22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B 4BCBC886'
+'2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A 062B3CF5 B3A278A6'
+'6D2A13F8 3F44F82D DF310EE0 74AB6A36 4597E899 A0255DC1 64F31CC5'
+'0846851D F9AB4819 5DED7EA1 B1D510BD 7EE74D73 FAF36BC3 1ECFA268'
+'359046F4 EB879F92 4009438B 481C6CD7 889A002E D5EE382B C9190DA6'
+'FC026E47 9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71'
+'60C980DD 98EDD3DF FFFFFFFF FFFFFFFF'),
g: hex('13'),
hash: 'sha256'}
};
const crypto = require('crypto'),
bigint = require('bigint'),
config = require('./config'),
assert = require('assert'),
ALG = config.get('alg_name'),
Put = require('put');
bignum = require('bignum'),
assert = require('assert');
const zero = bignum(0);
function assert_(val, msg) {
if (!val)
throw new Error(msg||"assertion");
}
/*

@@ -15,21 +19,54 @@ * If a conversion is explicitly specified with the operator PAD(),

* params:
* n (bigint) Number to pad
* N (bigint) N
* n (buffer) Number to pad
* len (int) length of the resulting Buffer
*
* returns: buffer
*/
var pad = exports.pad = function pad(n, N) {
// a Put padding is specified in bytes
var N_bytes = Math.ceil(N.bitLength() / 8);
var n_bytes = Math.ceil(n.bitLength() / 8);
var padding = N_bytes - n_bytes;
if (padding < 0) {
throw("Negative padding. Very uncomfortable.");
}
return Put()
.pad(padding)
.put(n.toBuffer())
.buffer();
function padTo(n, len) {
assertIsBuffer(n, "n");
var padding = len - n.length;
assert_(padding > -1, "Negative padding. Very uncomfortable.");
var result = new Buffer(len);
result.fill(0, 0, padding);
n.copy(result, padding);
assert.equal(result.length, len);
return result;
};
function padToN(number, params) {
assertIsBignum(number);
return padTo(number.toBuffer(), params.N_length_bits/8);
}
function padToH(number, params) {
assertIsBignum(number);
var hashlen_bits;
if (params.hash === "sha1")
hashlen_bits = 160;
else if (params.hash === "sha256")
hashlen_bits = 256;
else if (params.hash === "sha512")
hashlen_bits = 512;
else
throw Error("cannot determine length of hash '"+params.hash+"'");
return padTo(number.toBuffer(), hashlen_bits/8);
}
function assertIsBuffer(arg, argname) {
argname = argname || "arg";
assert_(Buffer.isBuffer(arg), "Type error: "+argname+" must be a buffer");
}
function assertIsNBuffer(arg, params, argname) {
argname = argname || "arg";
assert_(Buffer.isBuffer(arg), "Type error: "+argname+" must be a buffer");
if (arg.length != params.N_length_bits/8)
assert_(false, argname+" was "+arg.length+", expected "+(params.N_length_bits/8));
}
function assertIsBignum(arg) {
assert.equal(arg.constructor.name, "BigNum");
}
/*

@@ -42,19 +79,20 @@ * compute the intermediate value x as a hash of three buffers:

* params:
* s (buffer) salt
* salt (buffer) salt
* I (buffer) user identity
* P (buffer) user password
*
* returns: x (bignum) user secret
*/
var getx = exports.getx = function getx(s, I, P, alg) {
assert(Buffer.isBuffer(s), "Type error: salt (s) must be a buffer");
assert(Buffer.isBuffer(I), "Type error: identity (I) must be a buffer");
assert(Buffer.isBuffer(P), "Type error: password (P) must be a buffer");
alg = alg || ALG;
var hashIP = crypto.createHash(alg)
function getx(params, salt, I, P) {
assertIsBuffer(salt, "salt (salt)");
assertIsBuffer(I, "identity (I)");
assertIsBuffer(P, "password (P)");
var hashIP = crypto.createHash(params.hash)
.update(Buffer.concat([I, new Buffer(':'), P]))
.digest('binary');
var hashX = crypto.createHash(alg)
.update(s)
.digest();
var hashX = crypto.createHash(params.hash)
.update(salt)
.update(hashIP)
.digest('hex');
return bigint(hashX, 16);
.digest();
return bignum.fromBuffer(hashX);
};

@@ -73,14 +111,15 @@

* params:
* s (buffer) salt
* params (obj) group parameters, with .N, .g, .hash
* salt (buffer) salt
* I (buffer) user identity
* P (buffer) user password
* N (bigint) group parameter N
* g (bigint) generator
* alg (string) default = ALG
*
* returns: bigint
* returns: buffer
*/
var getv = exports.getv = function getv(s, I, P, N, g, alg) {
alg = alg || ALG;
return g.powm(getx(s, I, P, alg), N);
function computeVerifier(params, salt, I, P) {
assertIsBuffer(salt, "salt (salt)");
assertIsBuffer(I, "identity (I)");
assertIsBuffer(P, "password (P)");
var v_num = params.g.powm(getx(params, salt, I, P), params.N);
return padToN(v_num, params);
};

@@ -92,16 +131,13 @@

* params:
* N (bigint) group parameter N
* g (bigint) generator
* alg (string) default = ALG
* params (obj) group parameters, with .N, .g, .hash
*
* returns: bigint
* returns: bignum
*/
var getk = exports.getk = function getk(N, g, alg) {
alg = alg || ALG;
return bigint(
crypto
.createHash(alg)
.update(N.toBuffer())
.update(pad(g, N))
.digest('hex'), 16);
function getk(params) {
var k_buf = crypto
.createHash(params.hash)
.update(padToN(params.N, params))
.update(padToN(params.g, params))
.digest();
return bignum.fromBuffer(k_buf);
};

@@ -116,5 +152,5 @@

*
* returns: bigint
* returns: nothing, but runs callback with a Buffer
*/
var genKey = exports.genKey = function genKey(bytes, callback) {
function genKey(bytes, callback) {
// bytes is optional

@@ -130,3 +166,3 @@ if (arguments.length < 2) {

if (err) return callback (err);
return callback(null, bigint.fromBuffer(buf));
return callback(null, buf);
});

@@ -144,10 +180,15 @@ };

* params:
* v (bigint) verifier
* g (bigint) generator
* params (obj) group parameters, with .N, .g, .hash
* v (bignum) verifier (stored)
* b (bignum) server secret exponent
*
* returns: B (buffer) the server public message
*/
var getB = exports.getB = function getB(v, g, b, N, alg) {
alg = alg || ALG;
var k = getk(N, g, alg);
var r = k.mul(v).add(g.powm(b, N)).mod(N);
return r;
function getB(params, k, v, b) {
assertIsBignum(v);
assertIsBignum(k);
assertIsBignum(b);
var N = params.N;
var r = k.mul(v).add(params.g.powm(b, N)).mod(N);
return padToN(r, params);
};

@@ -161,26 +202,38 @@

* Note: for this implementation, we take that to mean 256/8 bytes.
*
* params:
* params (obj) group parameters, with .N, .g, .hash
* a (bignum) client secret exponent
*
* returns A (bignum) the client public message
*/
var getA = exports.getA = function getA(g, a, N) {
if (Math.ceil(a.bitLength() / 8) < 256/8) {
console.warn("getA: client key length", a.bitLength(), "is less than the recommended 256");
function getA(params, a_num) {
assertIsBignum(a_num);
if (Math.ceil(a_num.bitLength() / 8) < 256/8) {
console.warn("getA: client key length", a_num.bitLength(), "is less than the recommended 256");
}
return g.powm(a, N);
return padToN(params.g.powm(a_num, params.N), params);
};
/*
* Random scrambling parameter u
* getu() hashes the two public messages together, to obtain a scrambling
* parameter "u" which cannot be predicted by either party ahead of time.
* This makes it safe to use the message ordering defined in the SRP-6a
* paper, in which the server reveals their "B" value before the client
* commits to their "A" value.
*
* params:
* A (bigint) client ephemeral public key
* B (bigint) server ephemeral public key
* N (bigint) group parameter N
* params (obj) group parameters, with .N, .g, .hash
* A (Buffer) client ephemeral public key
* B (Buffer) server ephemeral public key
*
* returns: u (bignum) shared scrambling parameter
*/
var getu = exports.getu = function getu(A, B, N, alg) {
alg = alg || ALG;
return bigint(
crypto
.createHash(alg)
.update(pad(A, N))
.update(pad(B, N))
.digest('hex'), 16);
function getu(params, A, B) {
assertIsNBuffer(A, params, "A");
assertIsNBuffer(B, params, "B");
var u_buf = crypto.createHash(params.hash)
.update(A).update(B)
.digest();
return bignum.fromBuffer(u_buf);
};

@@ -192,18 +245,24 @@

* params:
* s (buffer) salt (read from server)
* params (obj) group parameters, with .N, .g, .hash
* salt (buffer) salt (read from server)
* I (buffer) user identity (read from user)
* P (buffer) user password (read from user)
* N (bigint) group parameter N (known in advance)
* g (bigint) generator for N (known in advance)
* a (bigint) ephemeral private key (generated for session)
* B (bigint) server ephemeral public key (read from server)
* a (bignum) ephemeral private key (generated for session)
* B (bignum) server ephemeral public key (read from server)
*
* returns: bigint
* returns: buffer
*/
var client_getS = exports.client_getS = function client_getS(s, I, P, N, g, a, B, alg) {
var A = getA(g, a, N);
var u = getu(A, B, N, alg);
var k = getk(N, g, alg);
var x = getx(s, I, P, alg);
return B.sub(k.mul(g.powm(x, N))).powm(a.add(u.mul(x)), N).mod(N);
function client_getS(params, k_num, x_num, a_num, B_num, u_num) {
assertIsBignum(k_num);
assertIsBignum(x_num);
assertIsBignum(a_num);
assertIsBignum(B_num);
assertIsBignum(u_num);
var g = params.g;
var N = params.N;
if (zero.ge(B_num) || N.le(B_num))
throw new Error("invalid server-supplied 'B', must be 1..N-1");
var S_num = B_num.sub(k_num.mul(g.powm(x_num, N))).powm(a_num.add(u_num.mul(x_num)), N).mod(N);
return padToN(S_num, params);
};

@@ -215,16 +274,20 @@

* params:
* s (bigint) salt (stored on server)
* v (bigint) verifier (stored on server)
* N (bigint) group parameter N (known in advance)
* g (bigint) generator for N (known in advance)
* A (bigint) ephemeral client public key (read from client)
* b (bigint) server ephemeral private key (generated for session)
* params (obj) group parameters, with .N, .g, .hash
* v (bignum) verifier (stored on server)
* A (bignum) ephemeral client public key (read from client)
* b (bignum) server ephemeral private key (generated for session)
*
* returns: bigint
* returns: bignum
*/
var server_getS = exports.server_getS = function server_getS(s, v, N, g, A, b, alg) {
var k = getk(N, g, alg);
var B = getB(v, g, b, N, alg);
var u = getu(A, B, N, alg);
return A.mul(v.powm(u, N)).powm(b, N).mod(N);
function server_getS(params, v_num, A_num, b_num, u_num) {
assertIsBignum(v_num);
assertIsBignum(A_num);
assertIsBignum(b_num);
assertIsBignum(u_num);
var N = params.N;
if (zero.ge(A_num) || N.le(A_num))
throw new Error("invalid client-supplied 'A', must be 1..N-1");
var S_num = A_num.mul(v_num.powm(u_num, N)).powm(b_num, N).mod(N);
return padToN(S_num, params);
};

@@ -236,15 +299,122 @@

* params:
* S (bigint) Session key
* params (obj) group parameters, with .N, .g, .hash
* S (buffer) Session key
*
* returns: bigint
* returns: buffer
*/
var getK = exports.getK = function getK(S, alg) {
alg = alg || ALG;
var S_pad = new Buffer(pad(S, N));
return bigint(
crypto
.createHash(alg)
.update(S_pad)
.digest('hex'), 16);
function getK(params, S_buf) {
assertIsNBuffer(S_buf, params, "S");
return crypto.createHash(params.hash)
.update(S_buf)
.digest();
};
function getM1(params, A_buf, B_buf, S_buf) {
assertIsNBuffer(A_buf, params, "A");
assertIsNBuffer(B_buf, params, "B");
assertIsNBuffer(S_buf, params, "S");
return crypto.createHash(params.hash)
.update(A_buf).update(B_buf).update(S_buf)
.digest();
}
function equal(buf1, buf2) {
// TODO: constant-time comparison. A drop in the ocean compared to our
// non-constant-time modexp operations, but still good practice.
return buf1.toString('hex') === buf2.toString('hex');
}
function Client(params, salt_buf, identity_buf, password_buf, secret1_buf) {
if (!(this instanceof Client)) {
return new Client(params, salt_buf, identity_buf, password_buf, secret1_buf);
}
assertIsBuffer(salt_buf, "salt (salt)");
assertIsBuffer(identity_buf, "identity (I)");
assertIsBuffer(password_buf, "password (P)");
assertIsBuffer(secret1_buf, "secret1");
this._private = { params: params,
k_num: getk(params),
x_num: getx(params, salt_buf, identity_buf, password_buf),
a_num: bignum.fromBuffer(secret1_buf) };
this._private.A_buf = getA(params, this._private.a_num);
}
Client.prototype = {
computeA: function computeA() {
return this._private.A_buf;
},
setB: function setB(B_buf) {
var p = this._private;
var B_num = bignum.fromBuffer(B_buf);
var u_num = getu(p.params, p.A_buf, B_buf);
var S_buf = client_getS(p.params, p.k_num, p.x_num, p.a_num, B_num, u_num);
p.K_buf = getK(p.params, S_buf);
p.M1_buf = getM1(p.params, p.A_buf, B_buf, S_buf);
p.u_num = u_num; // only for tests
p.S_buf = S_buf; // only for tests
},
computeM1: function computeM1() {
if (this._private.M1_buf === undefined)
throw new Error("incomplete protocol");
return this._private.M1_buf;
},
/*checkM2: function checkM2(M2) {
CHECK();
},*/
computeK: function computeK() {
if (this._private.K_buf === undefined)
throw new Error("incomplete protocol");
return this._private.K_buf;
}
};
function Server(params, verifier_buf, secret2_buf) {
if (!(this instanceof Server)) {
return new Server(params, verifier_buf, secret2_buf);
}
assertIsBuffer(verifier_buf, "verifier");
assertIsBuffer(secret2_buf, "secret2");
this._private = { params: params,
k_num: getk(params),
b_num: bignum.fromBuffer(secret2_buf),
v_num: bignum.fromBuffer(verifier_buf) };
this._private.B_buf = getB(params, this._private.k_num,
this._private.v_num, this._private.b_num);
}
Server.prototype = {
computeB: function computeB() {
return this._private.B_buf;
},
setA: function setA(A_buf) {
var p = this._private;
var A_num = bignum.fromBuffer(A_buf);
var u_num = getu(p.params, A_buf, p.B_buf);
var S_buf = server_getS(p.params, p.v_num, A_num, p.b_num, u_num);
p.K_buf = getK(p.params, S_buf);
p.M1_buf = getM1(p.params, A_buf, p.B_buf, S_buf);
//p.M2_buf = XXX;
p.u_num = u_num; // only for tests
p.S_buf = S_buf; // only for tests
},
checkM1: function checkM1(clientM1_buf) {
if (this._private.M1_buf === undefined)
throw new Error("incomplete protocol");
if (!equal(this._private.M1_buf, clientM1_buf))
throw new Error("client did not use the same password");
//return this._private.M2;
},
computeK: function computeK() {
if (this._private.K_buf === undefined)
throw new Error("incomplete protocol");
return this._private.K_buf;
}
};
module.exports = {
params: require('./params'),
genKey: genKey,
computeVerifier: computeVerifier,
Client: Client,
Server: Server
};
{
"name": "srp",
"description": "Secure Remote Password (SRP)",
"version": "0.0.4",
"version": "0.2.0",

@@ -9,4 +9,3 @@ "main": "index.js",

"scripts": {
"start": "server/server",
"test": "vows test/*.js --spec"
"test": "vows test/test*.js --spec"
},

@@ -16,6 +15,6 @@

"type": "git",
"url": "https://github.com/jedp/node-srp"
"url": "https://github.com/mozilla/node-srp"
},
"author": "Jed Parsons <jed@jedparsons.com>",
"author": "Brian Warner <warner-node-srp@lothar.com>",
"licence": "MIT",

@@ -25,8 +24,3 @@ "readmeFilename": "README.md",

"dependencies": {
"bigint": "0.4.2",
"convict": "0.0.6",
"express": "2.5.8",
"jade": "0.27.2",
"put": "0.0.6",
"request": "2.11.1"
"bignum": "0.6.1"
},

@@ -33,0 +27,0 @@

[![build status](https://secure.travis-ci.org/jedp/node-srp.png)](http://travis-ci.org/jedp/node-srp)
#SRP - Secure Remote Password
# SRP - Secure Remote Password

@@ -10,21 +10,14 @@ Implementation of the [SRP Authentication and Key Exchange

The goals are to provide at a minimum:
SRP is an interactive protocol which allows a server to confirm that some client knows a password, and to derive a strong shared session key, without revealing what the password is to an eavesdropper. In addition, the server does not hold the actual password: instead it stores a "verifier" created by the client. If the server's private data is revealed (by a server compromise), the verifier cannot be used directly to impersonate the client.
- [done] SRP function library that passes [RFC 5054 tests](http://tools.ietf.org/html/rfc5054#appendix-B)
- [done] SRP server
- [done] SRP test client
- SRP client lib for Node.js
- JavaScript browser client (maybe)
- Interoperability with [Mozilla Identity-Attached
Services](https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol)
This module provides both client and server implementations of SRP-6a for node.js. They are interoperable with [Mozilla Identity-Attached Services](https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol)
##Prerequisites
* [Installation](#installation)
* [Running Tests](#running-tests)
* [Usage](#how-to-use-it)
* [API Reference](#api-reference)
* [Resources](#resources)
[GNU libgmp](http://gmplib.org/) for those big big numbers.
## Installation
- debian: `libgmp3-dev`
- OSX brew: `gmp`
##Installation
`npm install srp`

@@ -34,3 +27,3 @@

##Tests
## Running Tests

@@ -43,107 +36,122 @@ Run `npm test`.

##Description of the Protocol
## How to use it
###Initial Setup
First, you must decide on the "parameters". This module provides a variety of pre-packaged parameter sets, at various levels of security (more secure parameters take longer to run). The "2048"-bit parameters are probably fairly secure for the near future. Both client and server must use the same parameters.
Carol the Client wants to share messages with Steve the server.
Before this can happen, they need to perform a one-time setup step.
var params = srp.params["2048"];
Carol and Steve agree on a large random number `N` and a generator
`g`. These can be published in advance or better yet hard-coded in
their implementations. They also agree on a cryptographic hashing
function `H`.
Each client will have a unique "identity" string. This is typically a username or email address. Clients will also use a unique "salt", which can be randomly generated during account creation. The salt is generally stored on the server, and must be provided to the client each time they try to connect.
Carol establishes a password and remembers it well. She the generates
some random salt, `s`, and compputes the verifier `v` as `g ^ H(s |
H(I | ':' | P)) % N`, where `I` is Carol's identity, and `|` denotes
concatenation.
Note that all APIs accept and return node.js Buffer objects, not strings.
Carol then sends Steve `I`, `s`, and `v`. She also sends the size of
`N` and the name of the hashing algorithm she has chosen.
### Client Setup: Account Creation
Steve stores `I`, `s`, and `v`. Carol remembers `P`. This sequence
is performed once, after which Carol and Steve can use the SRP
protocol to share messages.
The client feeds their identity string, password, and salt, into `computeVerifier`. This returns the Verifier buffer. The Verifier must be delivered to the server, typically during a "create account" process. Note that the Verifier can be used to mount a dictionary attack against the user's password, so it should be treated with care (and delivered securely to the server).
###Message Protocol
var verifier = srp.computeVerifier(params, salt, identity, password);
createAccount(identity, verifier);
First, Carol generates an ephemeral private key `a`. She computes the
public key `A` as `g^a % N`. She sends Steve `I` and `A`.
The server should store the identity, salt, and verifier in a table, indexed by the identity for later access. The server will provide the salt to anyone who asks, but should never reveal the verifier to anybody.
Client sends `I`, `A`.
### Login
Steve looks up `v` and `s`. Steve generates an ephemeral private key
`b` and computes the public key `B` as `k * v + g^b % N`, where `k` is
`H(N | PAD(g))`. (`PAD` designates a function that left-pads a byte
string with zeroes until it is the same size as `N`.) Steve sends `s`
and `B`.
Later, when the client wants to connect to the server, it starts by submitting its identity string, and retrieving the salt.
Server replies with `s` and `B`.
Then the client needs to create a secret random string called `secret1`, using `srp.genKey()`. The protocol uses this to make sure that each instance of the protocol is unique.
Both now compute the scrambling parameter `u` as `u = H(PAD(A) | PAD(B))`.
Then, create a new `srp.Client` instance with parameters, identity, salt, password, and `secret1`.
Now both Carol and Steve have the parameters they need to compute
their session key, `S`.
The client must then ask this object for the derived `srpA` value, and deliver srpA to the server.
For Carol, the formula is:
srp.genKey(function(secret1) {
var c = new srp.Client(params, salt, identity, password, secret1);
var srpA = c.computeA();
sendToServer(srpA);
});
```
S_client = (B - k * g^x) ^ (a + u * x)
```
Meanwhile, the server is doing something similar, except using the Verifier instead of the salt/identity/password, and using its own secret random string.
For Steve, the formula is:
srp.genKey(function(secret2) {
var s = new srp.Server(params, verifier, secret2);
var srpB = s.computeB();
sendToClient(srpB);
});
```
S_server = (A * v ^ u) ^ b
```
When the client receives the server's `srpB` value, it stuffs it into the Client instance. This allows it to extract two values: `M1` and `K`.
They both now compute the shared session key, `K`, as `H(S)`. (The
hash is taken to obscure any structure that may be visible in `S`.)
c.setB(srpB);
var M1 = c.computeM1();
sendToServer(M1);
var K = c.computeK();
Now Carol and Steve must convince each other that their values for `K`
match. Here, Carol hashes and hashes again her session key and sends
it to Steve. If he gets the same result when hashing his session key
twice, he hashes his session key once and sends it back to Carol, who
can check if she wishes that she gets the same value.
`M1` is a challenge value, created by the client and delivered to the server. After accepting the client's `A` value, the server can check `M1` to determine whether or not the client really knew the password. The server can also obtain its own `K` value.
###Glossary of Terms
s.setA(srpA)
s.checkM1(M1); // throws error if wrong
var K = s.computeK();
`N` a large prime number
If the password passed into `srp.Client()` is the same as the one passed into `srp.computeVerifier()`, then the server will accept `M1`, and the `K` on both sides will be the same.
`g` a generator
`K` is a strong random string, suitable for use as a session key to encrypt or authenticate subsequent messages.
`H` a secure hashing function
If the password was different, then `s.checkM1()` will throw an error, and the two `K` values will be unrelated random strings.
`|` the concatenation operator
The overall conversation looks like this:
`PAD` a function that left-pads a block of bytes with zeroes until it is the same length as `N`
Client: Server:
p = params["2048"] p = params["2048"]
s1 = genKey() s2 = genKey()
c = new Client(p,salt,id,pw,s1) s = new Server(p,verifier,s2)
A = c.computeA() A----> s.setA(A)
c.setB(B) <-----B B = s.computeB()
M1 = c.computeM1() M1----> s.checkM1(M1) // may throw error
K = c.computeK() K = s.computeK()
`I` the identity of the client (a string)
### What a "Session" Means
`P` the password of the client (a string)
Basic login can be done by simply calling `s.checkM1()`: if it doesn't throw an exception, the client knew the right password. However, by itself, this does not bind knowledge of the password to anything else. If the A/B/M1 values were delivered over an insecure channel, controlled by an attacker, they could simply wait until `M1` was accepted, and then take control of the channel.
`s` some random salt (a string)
Delivering these values over a secure channel, such as an HTTPS connection, is better. If the HTTP client correctly checks the server certificate, and the certificate was correctly issued, then you can exclude a man-in-the-middle attacker.
`v` the verifier
The safest approach is to *create* a secure channel with the generated session key `K`, using it to encrypt and authenticate all the messages which follow.
`k` a multiplier, `H(N | PAD(g))`
## API Reference
`u` a scrambling parameter
Module contents:
`a` an ephemeral private key known to the client
- **`params[]`**
- table of parameter sets. Pass a property from this object into the Client and Server constructors.
- **`genKey(numBytes, callback)`**
- async function to generate the ephemeral secrets passed into the Client and Server constructors.
- **`computeVerifier(params, salt, identity, password) -> V`**
- produces a Verifier, which should be given to the server during account creation. The Verifier will be passed into the Server constructor during login.
- **`Client(params, salt, identity, password, secret1) -> c`**
- constructor for the client-side of SRP. secret1 should come from genKey(). The Client object has the following methods:
- **`Server(params, verifier, secret2) -> s`**
- constructor for the server-side of SRP. secret2 should come from genKey(). If the Server object must be persisted (e.g. in a database) between protocol phases, simply store secret2 and re-construct the Server with the same values. The Server object has the following methods:
`A` the public key from `a`
`Client` methods:
`b` an ephemeral private key known to the server
- **`computeA() -> A`**
- produce the A value that will be sent to the server.
- **`setB(B)`**
- this accepts the B value from the server. M1 and K cannot be accessed until setB() has been called.
- **`computeM1() -> M1`**
- produce the M1 key-confirmation message. This should be sent to the server, which can check it to make sure the client really knew the correct password. setB must be called before computeM1.
- **`computeK() -> K`**
- produce the shared key K. If the password and verifier matched, both client and server will get the same value for K. setB must be called before computeK.
`B` the public key from `b`
`Server` methods:
`x` an intermediate value, `H(s | H(I | ":" | P))`
- **`computeB() -> B`**
- produce the B value that will be sent to the client.
- **`setA(A)`**
- this accepts the A value from the client. checkM1 and computeK cannot be called until setA has been called.
- **`checkM1(M1)`**
- this checks the client's M1 key-confirmation message. If the client's password matched the server's verifier, checkM1() will complete without error. If they do not match, checkM1() will throw an error.
- **`computeK() -> K`**
- produce the shared key K. setB must be called before computeK.
`S` the session key
## Resources
`K` a hash of the session key shared between client and server
##Resources
- [The Stanford SRP Homepage](http://srp.stanford.edu/)

@@ -154,4 +162,4 @@ - RFC 2945: [The SRP Authentication and Key Exchange System](http://tools.ietf.org/html/rfc2945)

##License
## License
MIT
const vows = require('vows'),
assert = require('assert'),
bigint = require('bigint'),
Put = require('put'),
params = require('../lib/params'),
bignum = require('bignum'),
srp = require('../lib/srp');

@@ -14,133 +12,298 @@

*
* Note that P_stretched is the HKDF-stretched key, computed elsewhere.
* Note that P is the HKDF-stretched key, computed elsewhere.
*/
const I = new Buffer("andré@example.org", "utf8"),
P = new Buffer("pässwörd", "utf8"),
P_stretch = new Buffer("5b597db713ef1c0567f8d053e9dde294f917a0a838ddb661a98a67a188bdf491", "hex");
N = params['2048'].N,
g = params['2048'].g,
s = new Buffer("00f100000000000000000000000000000000000000000000000000000000009b", 'hex'),
b = bigint("119827766042000957856349411550091527197081252269605447689936430952278002910536155503035277450562560602971778328003253459733139844872578335969641434172163891575825549320284149937367218831553428069327423189198736863575142046053414928395487318790431357183095397064892915732142348352729476798883594253343430842313006332606344714480994398088610693164826214242314090883070476916770009839296811772743420990997238759832829219109897328764288319854878234173127723999262829546938957845836323714648638545526799188280210660508721582004031026248318155961400949332162983284562611677708050444470403904739431335617585333671378812960", 10),
a = bigint("119334647663227291363113405741243413916434827363146166012200067038894142816254113710841716638008805209543910927476491099816542561560345503311330152550056221240122563520612198703057065667637570340647063422988042473190059156975005813463818646696643573820202000369152615667401021816298491297653620614440782978764393137821956464627163145421579373439868081673415678986432326806001408975760610901250649711198896213496068605039486228645916762983047459546900860937537468108474188471985145427757080362211874088739962880012800917057512380049765406348391068882236386645531489818952050236879990719946264951520393624479315530076", 10),
ALG = 'sha256';
function join(s) {
return s.split(/\s/).join('');
}
function decimal(s) {
return bignum(join(s), 10).toBuffer();
}
function h(s) {
return new Buffer(join(s), 'hex');
}
/* The constants below are the expected computed SRP values given the
* parameters specified above for I, P, N, g, b, a, and the algorithm.
const params = srp.params['2048'];
/* inputs_1/expected_1 are the main PiCl test vectors. They were mechanically
* generated to force certain derived values (stretched-password "P", v, A,
* B, and S) to begin with a 0x00 byte (to exercise padding bugs).
*/
const I_hex = "616e6472c3a9406578616d706c652e6f7267",
P_hex = "70c3a4737377c3b67264",
k = bigint("2590038599070950300691544216303772122846747035652616593381637186118123578112", 10),
x_hex = "ffd36e11f577d312892334810d55089cb96c39443c255a9d85874bb6df69a537",
x = bigint("115713340795669212831971819661984296758573939625477265918747447380376082294071", 10),
v = bigint("71059715947322363168818619231596014948502664753879821526306672648301269136332546839100253983803912725413731153916626297948231925131054776204301203872383833825292863403260680360596134078965569670569235971894130915251144385164054999200238790399524380121634022271328529734937174066811503227222944678351915275352511787735824142082281320032065951325711784707869987141733046865019265053926187756870781628009053137574167426864838849814321621297918109241151570638074596222682772158532484976644908876686423788254204401136102193244276625617385185761349298945899736743346225452678822123821266140913290180513540399852050747986", 10),
v_hex = "00901a4e05a7986cfafe2c80993f6e21847d38b8b9168065149480722d008c9ac5fe418d799d03c2b1c26db2afcd45130a0601d310faa060cc728888aba130a17d855773107ecc92f31ea3a3838bc72777fc26420ed59918298583d15640b965939dd6967e943bd6ed846dbbb18885c74f6e9370e4eeecc4c8e2a648850cf2ba5baab18888b433c4b0bd8891eeffe16cc022a098284696bc3a81e735a1a2a37162f62b980879bbd403ae55548b9feeecb18bf0740f0d078a435fedb5324d630e8a14fed435fbb5ea4b6e94b8b129799d2a0991671a67be34149dc5e94a4a3d05749fc3b9e1a5328296b20a15348420bed2f28d2558cb4099f30be8a7240c9252",
b_hex = "00f30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020",
B_hex = "00857f70b197a6f3f79c4270a41c581d62c7ec7fc554c797481d4b4075b06be3df7f4f189e71fbec08d1bcff8c5e4f7465256cba8a78b725daa0b9bddcbbea43d916067b12c59aaf4a9cdad53e08e4a5770ea722879873022c5f5f608eb94795710a907e1b425080688d9e7790ce07816e6b2cdb9ad2c18f60a2a5feb91b6da392579c5eb1e36f425b85c34085b216b97c4a3f7ffeb887c878ce0152d8be66eb9c7a51abbae3b3f656c6e56d95d3e148a23af3e9aaa54c72cde19b58bdcbfb34b9eb7f6dcbcd86e27e6221f6d3da2517255088f5e7c408b37d6765120134b71986287225d781c49ae5436b89525e17ebdcb8f3b7eb43163acfb31c45a51a5267",
a_hex = "00f2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000115c",
A_hex = "00f2a357d7da71321be6c070fb3a59288cec951cb13e76451f8c466ab373626a7272dc1484c79ea3cd1ea32e57fa46652e6450aa61ac5ee7eac7a8c06c28ab195ccbe57500062c501a15fbb23a7f71b235448326af5e51c063f167378c78213793dbc54efb32f204de753d7a6b3d826daaefc007d17862af9b6a14e35f17f1eb8b13c7b8ffa1f6f47b70d62bd0c351b47596b0b0abcba95c2d731869ed6e4ec24ab90da8cb22e65d256315ee84d8079b4086d90c4e827b51bb4e4d2d7b387da02e6b48904a3ba6d7648a9bcdf3e9fc607cfba92f8eacae123ac45a79307cf3dd281ed75a96c7de8fcd823f148dcc06349795f825fb029859b963ab88320133de",
u_hex = "610c6df1f495e4298a2a59a0f5b00d47ea2ed6ce2ccec8f7ade158314a7bd794",
S_hex = "009cc8da2f7a95015bc0091faa36d6efff52c33b924353e11de1d8e738654d6f6a481003acb17cae2ba2d4ae3fea84314c940397640fce92d9153dffb7f3bd29cbdb49e4ff0d26c467061337fd3708514e3039d24cb54dc46420426b0daf772463fe06eb1521c7b096c4eeb6e5f9f73949dcc74bc91baab8398aff6df6735da2c9486a645a20f2d7d8f455a2bd226f21e127f23e202b21fdd4ef64dc1a6740b6fcd2a6b032fcb393a2b9d97506b6fb895585d29173cc0e89c3b3077ffa31215db602b28364f8101246ee9e8c47b63881f3f867e67971825df6a881d1142989abcd4abba9c27ae529c31be53f69966ccb81f7660f95d5f8fc45d052df3bcbb761",
M1_hex = "182ff26523922c52559cab3cdfc89a74c986b1d7504ea53d11d9a204fc54449d",
K_hex = "78a36d3e0df089e729a98dee3290fc4964cd6ec96b771d6abb6efe9181be868b";
const inputs_1 = {
I: new Buffer('andré@example.org', 'utf8'),
P: h('00f9b71800ab5337 d51177d8fbc682a3 653fa6dae5b87628 eeec43a18af59a9d'),
salt: h('00f1000000000000000000000000000000000000000000000000000000000179'),
// a and b are usually random. For testing, we force them to specific values.
a: h(' 00f2000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 000000000000d3d7'
),
b: h(' 00f3000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 000000000000000f'
)
};
function pad(s, margin) {
margin = margin || 256;
// We consistently zero-pad all string values to 256 bytes (2048 bits)
var padding = margin - (s.length % margin)
var prefix = "";
while (padding-- > 0) {
prefix += "0";
}
return prefix + s;
const expected_1 = {
// 'k' encodes the group (N and g), used in SRP-6a
k: decimal('2590038599070950300691544216303772122846747035652616593381637186118123578112'),
// 'x' is derived from the salt and password
// 'v' is the SRP verifier
x: h('b5200337cc3f3f92 6cdddae0b2d31029 c069936a844aff58 779a545be89d0abe'),
v: h(' 00173ffa0263e63c cfd6791b8ee2a40f 048ec94cd95aa8a3 125726f9805e0c82'
+'83c658dc0b607fbb 25db68e68e93f265 8483049c68af7e82 14c49fde2712a775'
+'b63e545160d64b00 189a86708c69657d a7a1678eda0cd79f 86b8560ebdb1ffc2'
+'21db360eab901d64 3a75bf1205070a57 91230ae56466b8c3 c1eb656e19b794f1'
+'ea0d2a077b3a7553 50208ea0118fec8c 4b2ec344a05c66ae 1449b32609ca7189'
+'451c259d65bd15b3 4d8729afdb5faff8 af1f3437bbdc0c3d 0b069a8ab2a959c9'
+'0c5a43d42082c774 90f3afcc10ef5648 625c0605cdaace6c 6fdc9e9a7e6635d6'
+'19f50af773452247 0502cab26a52a198 f5b00a2798589165 07b0b4e9ef9524d6'),
// 'B' is the server's public message
B: h(' 0022ce5a7b9d8127 7172caa20b0f1efb 4643b3becc535664 73959b07b790d3c3'
+'f08650d5531c19ad 30ebb67bdb481d1d 9cf61bf272f84398 48fdda58a4e6abc5'
+'abb2ac496da5098d 5cbf90e29b4b110e 4e2c033c70af7392 5fa37457ee13ea3e'
+'8fde4ab516dff1c2 ae8e57a6b264fb9d b637eeeae9b5e43d faba9b329d3b8770'
+'ce89888709e02627 0e474eef822436e6 397562f284778673 a1a7bc12b6883d1c'
+'21fbc27ffb3dbeb8 5efda279a69a1941 4969113f10451603 065f0a0126666456'
+'51dde44a52f4d8de 113e2131321df1bf 4369d2585364f9e5 36c39a4dce33221b'
+'e57d50ddccb4384e 3612bbfd03a268a3 6e4f7e01de651401 e108cc247db50392'),
// 'A' is the client's public message
A: h(' 007da76cb7e77af5 ab61f334dbd5a958 513afcdf0f47ab99 271fc5f7860fe213'
+'2e5802ca79d2e5c0 64bb80a38ee08771 c98a937696698d87 8d78571568c98a1c'
+'40cc6e7cb101988a 2f9ba3d65679027d 4d9068cb8aad6ebf f0101bab6d52b5fd'
+'fa81d2ed48bba119 d4ecdb7f3f478bd2 36d5749f2275e948 4f2d0a9259d05e49'
+'d78a23dd26c60bfb a04fd346e5146469 a8c3f010a627be81 c58ded1caaef2363'
+'635a45f97ca0d895 cc92ace1d09a99d6 beb6b0dc0829535c 857a419e834db128'
+'64cd6ee8a843563b 0240520ff0195735 cd9d316842d5d3f8 ef7209a0bb4b54ad'
+'7374d73e79be2c39 75632de562c59647 0bb27bad79c3e2fc ddf194e1666cb9fc'),
// 'u' combines the two public messages
u: h('b284aa1064e87751 50da6b5e2147b47c a7df505bed94a6f4 bb2ad873332ad732'),
// 'S' is the shared secret
S: h(' 0092aaf0f527906a a5e8601f5d707907 a03137e1b601e04b 5a1deb02a981f4be'
+'037b39829a27dba5 0f1b27545ff2e287 29c2b79dcbdd32c9 d6b20d340affab91'
+'a626a8075806c26f e39df91d0ad979f9 b2ee8aad1bc783e7 097407b63bfe58d9'
+'118b9b0b2a7c5c4c debaf8e9a460f4bf 6247b0da34b760a5 9fac891757ddedca'
+'f08eed823b090586 c63009b2d740cc9f 5397be89a2c32cdc fe6d6251ce11e44e'
+'6ecbdd9b6d93f30e 90896d2527564c7e b9ff70aa91acc0ba c1740a11cd184ffb'
+'989554ab58117c21 96b353d70c356160 100ef5f4c28d19f6 e59ea2508e8e8aac'
+'6001497c27f362ed bafb25e0f045bfdf 9fb02db9c908f103 40a639fe84c31b27'),
// 'K' is the shared derived key
K: h('e68fd0112bfa31dc ffc8e9c96a1cbadb 4c3145978ff35c73 e5bf8d30bbc7499a'),
// 'M1' is the client's proof that it knows the shared key
M1: h('27949ec1e0f16256 33436865edb037e2 3eb6bf5cb91873f2 a2729373c2039008')
};
vows.describe('picl vectors')
/* inputs_2/expected_2 have leading 0x00 bytes in 'x' and 'u' */
const inputs_2 = {
I: inputs_1.I, P: inputs_1.P,
salt: h('00f1000000000000000000000000000000000000000000000000000000000021'),
a: h(' 00f2000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 000000000000000d'
),
b: h(' 00f3000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000001'
)
};
const expected_2 = {
k: expected_1.k,
x: h('009b2740fb49284d 69cab7c916d449ee d7dcabf41332b8b8 d6928f529bd1a94e'),
v: h(' 1cd8b856685672ee 7a5895d897121234 6c17c3472f2696e4 8cdeec5533c06693'
+'179bc24802b762bc c1e1f8fc8abe607a f2f44aac9172e7dd 0c0110e45cf3b700'
+'f8db153b67fb0e76 3c6710b8c1c26baf c3b67a50652ee0d7 c6045a5c4b51ff33'
+'d0135065dca5d6bb 7e150e07414bd572 a954471059c1b466 d0530b0a80bd2d0c'
+'f1bedf5abfc05c3c f2736ac40b083dcf 62271e834042ecb0 d4882ddd35403c1e'
+'d24bc4ffe274c5f6 be50ec9b85aa0cfa 26d97e086ec45e06 3c29174d3dbe5490'
+'1d2a557b7eb46b18 9e17cc721fc098a0 baee2f364a2b409d 49d9372a9625db11'
+'acfd74ba7f41285f 9c1916d3caaf5238 852694bbde2a13f7 8fcc92d16658dd04'),
// 'B' is the server's public message
B: h(' 485d56912c60d9c1 7af15494d4d50006 45eefa2d41f6bcb5 785e08efad0833a1'
+'3cb43ee3869e78d4 c2006f42b9741782 a85c90a110cc9a74 4fc2a361d5535966'
+'2dc5fa4a8d0c7c0e 63e0cf32a28af655 863dd5d66f550557 eacd3e3e64d90f9f'
+'0d757403c9bbfb08 fcc9a35e1cb421d7 3bb93fa72d5b54ed bfa219d3867255ba'
+'f96223eef038f085 722b2d14457a5a13 1857a56e66d3011b b5aa7504c4b9a346'
+'8d0ebdd817d20105 be06ba261ea16740 723faa097f27ddc2 efe34cf8fe59451a'
+'5bb3987d7161085f b8fc28d5cc28c466 6a3ca486ad0ca83d 1984248ac838574e'
+'348fb9745ffd1163 f53b5566768a8971 237065d8f6e786be e15107125fb10df1'),
// 'A' is the client's public message
A: h(' a4b17836b1e7d6f1 5b9901f644bcdf5e 119e7a861c6ee88d 006d8420a5066f22'
+'d9bf5ccf3d380437 0d29d778ec40afcf c88de7bf22ec03fc 6ab12e0dd95d15e3'
+'a6249c94393435b0 0d23b1b0439dabed cce1726b2b3cdea2 647c8790d604d87d'
+'2ac890cfceec0dbe 434f09a9bc11d984 a1e1990f69956ae0 db6068992ad1715f'
+'b4381516da83637a 73de4211908c8f2f f8b3a09e8535acf3 c2b8de4e9a632f89'
+'9bfa08cee543b4ea 50d0aca0b3e4fbfa e49ffa2a1ab89a42 8bea928868828501'
+'2e8af13fcdd444ad da9ad1d0ab4c2069 91919e5391bd2b1a ab8c2d006baceaf8'
+'cdcb555a6b16e844 5b03e09776eba841 7576dac458afbbd5 2902dfb0282bed79'),
// 'u' combines the two public messages
u: h('000e4039be3989ad 088dc17d8ade899a 6409e7e57b3e8518 cee1cbc77e1de243'),
// 'S' is the shared secret
S: h(' 5c7f591d134d19f9 fcedc2b4e3eecd3d 5deadfe7dd42bd59 b1c960516c65ab61'
+'d007f8134e0a7ca3 0dd409128ef2c780 6784afd95985c8f3 c2d42cd73d26d315'
+'541645d28aefabc9 980c9a6e5714b178 aa69e5321828ca00 f3d10d742776cfe4'
+'4b7f5f5c0247addc 0ab0640b49b540ff 9bccea8702e1f996 49448680c00fb484'
+'51919224d44236ba 1b1e5cf62a5946bd 637f189ff7b8eba9 7b719f18ad9251f0'
+'a81c157604065388 d7bf4abbf774bfb2 d7b95ed8359b0d70 6ff5df0223992c81'
+'4aac506e1bace002 d134ed5e41d74f93 a8f410dfe7dc5954 f70b6bafcd0ddfde'
+'e75f0058f718ec14 f9bbeb29ff966e00 ddfdd2d38a1c7a68 ac455a57b972d528'),
// 'K' is the shared derived key
K: h('b637ede0b7a31c46 b2567e855eb8a7f7 a994937deee76479 62afbe35d6929709'),
// 'M1' is the client's proof that it knows the shared key
M1: h('67c83797eb1a3987 e2d48d287e3bd772 d25db2b3cd86ea22 c8cf3ae932a1e45b')
};
.addBatch({
'test vectors': {
'I encoding': function() {
assert(I.toString('hex') == I_hex);
},
/* inputs_3/expected_3 have leading 0x00 bytes in 'x' and 'K' */
const inputs_3 = {
I: inputs_2.I, P: inputs_2.P,
salt: h('00f1000000000000000000000000000000000000000000000000000000000021'),
a: h(' 00f2000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 00000000000001a0'
),
b: inputs_2.b
};
const expected_3 = {
k: expected_2.k,
x: expected_2.x,
v: expected_2.v,
B: expected_2.B,
A: h(' 87b6da9e4162843b 4d5ee60c403ae3e1 e9fdab64883f13ab 4a44b0718a9ea1b6'
+'1ad17c675e0f0395 b37d58a046a2d5ab 1fb665a9777abe80 8077ccf6fd8ec583'
+'854eab98deb257d9 10e5bf5cafed4955 2a5cd9927c0979f7 5a21654644000173'
+'aef6f2244296439c 10b3c61a03e7146e f6c9c9564b1d2bf5 1ece84d115965f9c'
+'c82006bdb7a124da 3304bcc24c8f3724 522b748fb19a0cb6 b60e355acbf649b5'
+'40b4972e24077c29 32004a3ad9e59464 2e90a3bfc8de7085 f4a4efc195bd06c9'
+'6c7011f3c979eaab 469f06465a5b7239 afaee535aedc5bd2 1a220546e0e6b70b'
+'5b6f54db3fea46d5 7ebc7fe46156d793 c59e6290d3cf9bc2 4316528da34f4640'),
u: h('865d0efca6cf17d6 f489e129231f1a48 b20c83ec6581d11f 3a2fa48ea93cd305'),
S: h(' 0ae26456e1a0dec1 ce162fb2e5bc7300 3c285e17c0b44f03 7ebbc57f8020ceae'
+'5d10a9e6e44eab2a 6915b582ab5f6e7d 16002ce05e524015 e9bc7c56d5131da4'
+'d4c4d7c3debaffcd b60e58468bd2c0da 5de95855480190a3 5258c79032001882'
+'3d836ca91848c5b6 3ca4265c3329eb44 161af9ce64cf4468 ef0eb88a788a0d07'
+'52a69821278c94ae 7193161b5c638b55 bf732e2a5996ccc5 16335f9f3d00dfa9'
+'8ac1b1e4971c5417 d34eba1e2a90ed60 a07d1d8be5b9d773 d8f2cb03bfb75994'
+'249f7734081aa42d 58dd54f8f725b245 175cf7d102e1086c eba4cfe7e49a2d27'
+'ffd6aef7549d402f bfcea78b4f3398ac 9ab1ee199f70acb6 4d2a17e159ff500d'),
K: h('00217598a4008956 4b17196bd43422d6 03a0a88a545b61b3 98c42c9cbcc1d1b3'),
M1: h('96d815ecece1dff4 254cd77517b37b97 65e741c1a57169ab af538e867444ec7f')
};
'P encoding': function() {
assert(P.toString('hex') == P_hex);
},
/* inputs_4/expected_4 have leading 0x00 bytes in 'x' and 'M1' */
const inputs_4 = {
I: inputs_2.I, P: inputs_2.P,
salt: h('00f1000000000000000000000000000000000000000000000000000000000021'),
a: h(' 00f2000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000000'
+'0000000000000000 0000000000000000 0000000000000000 0000000000000190'
),
b: inputs_2.b
};
const expected_4 = {
k: expected_2.k,
x: expected_2.x,
v: expected_2.v,
B: expected_2.B,
A: h(' 4aee66beefb92d12 c8e341814809afcd 9ce083c11abcda70 0c03d5379c429cb9'
+'acbde6bb42a628f3 7a2536c864c40f74 f48a9d9356029a8b fe0e10cb9cf5a8a4'
+'2e591841f426d281 edf7c9b04112d8ef bf73f9768a4faace ddd351d3e9380bf1'
+'dcd0590c7ab50a95 bd23e9617e303bea 6f8fbe8a657b6417 4b60cdf5c059ba67'
+'1b6735324ae0c30a e7f3e361de8f273c af7b2513fa048ed1 0106c66ce460c5cc'
+'78544c790f5ffcce 378b79d5f02ec361 3a457b03fa0cc39c 80d6fdd645e24f65'
+'c690f9478d5b331d c00eef68670edbf3 629fd1a6c85267d2 cbb90f1670e7ba09'
+'cf2b5a9b00be8e11 f33e47a1c1f04eca f35bccb61af1116e 4d0f9d475017bad2'),
u: h('d0913eb75b61e15a 87756ffa04d4f967 e492bd0b330a2b11 fe8976aada2bb1ee'),
S: h(' 7ba3ce4a3d236b95 3c2d0fee42195c85 081664a44f55b82d a3abf66ac68bdbd7'
+'ad82d5ad95090782 5241fb706de8fc58 0a29e4579fbbedf3 0bec0138b3f76e06'
+'f9c86b16ad673890 3003ce8c86cb14ea 552db904a20970a9 7d9258a768087d30'
+'47a6e77520d32968 de3f64e94cd8c463 92c13e194194745c 8e53a9bb15a79473'
+'2a645068970fcdd9 a7c98b4aec19773a 5196802c2e932e71 d3a4a340e6f4fe16'
+'9e7ccc687f7246fe 20edeaf88d1125da c812751317f7213c d84f9efe2313d701'
+'d4a9bf0242bfe703 26fc19b68c90e83b 59b5cc21886ab602 f8bfa16fb50c3147'
+'9aad5e31698abf67 863b7ca6b6ac25a7 09a24d8f94c80bbf 691e38c81beb3c72'),
K: h('bd2a167a93b8496e 68c7e24b37956924 672eb8249d25c281 13984912d5cf27a6'),
M1: h('00cef66a047d506c bf941c236218e583 5343534ae08cf0cd 0fb7980bed242e05')
};
'k': function() {
assert(k.eq(srp.getk(N, g, ALG)));
},
'x': function() {
assert(x.toString(16) == x_hex);
assert(srp.getx(s, I, P_stretch, ALG).eq(x));
},
function hexequal(a, b, msg) {
assert.equal(a.length, b.length, msg);
assert.equal(a.toString('hex'), b.toString('hex'), msg);
}
'v': function() {
assert(pad(v.toString(16)) == v_hex);
assert(srp.getv(s, I, P_stretch, N, g, ALG).eq(v));
},
function numequal(a, b, msg) {
assert(a.eq(b), msg);
}
'b': function() {
assert(pad(b.toString(16)) == b_hex);
},
function checkVectors(params, inputs, expected) {
hexequal(inputs.I, new Buffer('616e6472c3a9406578616d706c652e6f7267', "hex"), "I");
hexequal(srp.computeVerifier(params, inputs.salt, inputs.I, inputs.P), expected.v, "v");
'a': function() {
assert(pad(a.toString(16)) == a_hex);
},
var client = new srp.Client(params, inputs.salt, inputs.I, inputs.P, inputs.a);
var server = new srp.Server(params, expected.v, inputs.b);
'B': function() {
var B = srp.getB(v, g, b, N, ALG);
assert(pad(B.toString(16)) == B_hex);
},
numequal(client._private.k_num, bignum.fromBuffer(expected.k), "k");
numequal(client._private.x_num, bignum.fromBuffer(expected.x), "x");
hexequal(client.computeA(), expected.A);
hexequal(server.computeB(), expected.B);
'A': function() {
var A = srp.getA(g, a, N);
assert(pad(A.toString(16)) == A_hex);
},
assert.throws(function() {client.computeM1();}, /incomplete protocol/);
assert.throws(function() {client.computeK();}, /incomplete protocol/);
assert.throws(function() {server.checkM1(expected.M1);}, /incomplete protocol/);
assert.throws(function() {server.computeK();}, /incomplete protocol/);
'u': function() {
var A = bigint(A_hex, 16);
var B = bigint(B_hex, 16);
var u = srp.getu(A, B, N, ALG);
assert(u.toString(16) == u_hex);
},
client.setB(expected.B);
numequal(client._private.u_num, bignum.fromBuffer(expected.u));
hexequal(client._private.S_buf, expected.S);
hexequal(client.computeM1(), expected.M1);
hexequal(client.computeK(), expected.K);
'secrets': {
'client': {
topic: function() {
var B = bigint(B_hex, 16);
return srp.client_getS(s, I, P_stretch, N, g, a, B, ALG);
},
server.setA(expected.A);
numequal(server._private.u_num, bignum.fromBuffer(expected.u));
hexequal(server._private.S_buf, expected.S);
assert.throws(function() {server.checkM1(Buffer("notM1"));},
/client did not use the same password/);
server.checkM1(expected.M1); // happy, not throwy
hexequal(server.computeK(), expected.K);
}
'S': function(S) {
assert(pad(S.toString(16)) == S_hex);
},
vows.describe('picl vectors')
'K': function(S) {
assert(srp.getK(S, ALG).toString(16) == K_hex);
}
},
'server': {
topic: function() {
var A = bigint(A_hex, 16);
return srp.server_getS(s, v, N, g, A, b, ALG);
},
'S': function(S) {
assert(pad(S.toString(16)) == S_hex);
},
'K': function(S) {
assert(srp.getK(S, ALG).toString(16) == K_hex);
}
}
}
}
.addBatch({
'vectors 1': function() { checkVectors(params, inputs_1, expected_1); },
'vectors 2': function() { checkVectors(params, inputs_2, expected_2); },
'vectors 3': function() { checkVectors(params, inputs_3, expected_3); },
'vectors 4': function() { checkVectors(params, inputs_4, expected_4); }
})
.export(module);
const vows = require('vows'),
assert = require('assert'),
bigint = require('bigint'),
params = require('../lib/params'),
srp = require('../lib/srp');
srp = require('../lib/srp'),
params = srp.params['1024'];

@@ -13,33 +12,35 @@ /*

P = new Buffer("password123"),
s = bigint('BEB25379 D1A8581E B5A72767 3A2441EE', 16).toBuffer(),
N = params['1024'].N,
g = params['1024'].g,
k_expected = bigint('7556AA04 5AEF2CDD 07ABAF0F 665C3E81 8913186F', 16),
x_expected = bigint('94B7555A ABE9127C C58CCF49 93DB6CF8 4D16C124', 16),
v_expected = bigint('7E273DE8 696FFC4F 4E337D05 B4B375BE B0DDE156 9E8FA00A 9886D812'
+'9BADA1F1 822223CA 1A605B53 0E379BA4 729FDC59 F105B478 7E5186F5'
+'C671085A 1447B52A 48CF1970 B4FB6F84 00BBF4CE BFBB1681 52E08AB5'
+'EA53D15C 1AFF87B2 B9DA6E04 E058AD51 CC72BFC9 033B564E 26480D78'
+'E955A5E2 9E7AB245 DB2BE315 E2099AFB', 16),
s = Buffer('beb25379d1a8581eb5a727673a2441ee', 'hex'),
k_expected = '7556aa045aef2cdd07abaf0f665c3e818913186f',
x_expected = '94b7555aabe9127cc58ccf4993db6cf84d16c124',
v_expected = ('7e273de8 696ffc4f 4e337d05 b4b375be b0dde156 9e8fa00a 9886d812'
+'9bada1f1 822223ca 1a605b53 0e379ba4 729fdc59 f105b478 7e5186f5'
+'c671085a 1447b52a 48cf1970 b4fb6f84 00bbf4ce bfbb1681 52e08ab5'
+'ea53d15c 1aff87b2 b9da6e04 e058ad51 cc72bfc9 033b564e 26480d78'
+'e955a5e2 9e7ab245 db2be315 e2099afb').split(/\s/).join(''),
a = bigint('60975527 035CF2AD 1989806F 0407210B C81EDC04 E2762A56 AFD529DD DA2D4393', 16),
b = bigint('E487CB59 D31AC550 471E81F0 0F6928E0 1DDA08E9 74A004F4 9E61F5D1 05284D20', 16),
A_expected = bigint('61D5E490 F6F1B795 47B0704C 436F523D D0E560F0 C64115BB 72557EC4'
+'4352E890 3211C046 92272D8B 2D1A5358 A2CF1B6E 0BFCF99F 921530EC'
+'8E393561 79EAE45E 42BA92AE ACED8251 71E1E8B9 AF6D9C03 E1327F44'
+'BE087EF0 6530E69F 66615261 EEF54073 CA11CF58 58F0EDFD FE15EFEA'
+'B349EF5D 76988A36 72FAC47B 0769447B', 16),
B_expected = bigint('BD0C6151 2C692C0C B6D041FA 01BB152D 4916A1E7 7AF46AE1 05393011'
+'BAF38964 DC46A067 0DD125B9 5A981652 236F99D9 B681CBF8 7837EC99'
+'6C6DA044 53728610 D0C6DDB5 8B318885 D7D82C7F 8DEB75CE 7BD4FBAA'
+'37089E6F 9C6059F3 88838E7A 00030B33 1EB76840 910440B1 B27AAEAE'
+'EB4012B7 D7665238 A8E3FB00 4B117B58', 16),
a = Buffer('60975527035cf2ad1989806f0407210bc81edc04e2762a56afd529ddda2d4393', 'hex'),
b = Buffer('e487cb59d31ac550471e81f00f6928e01dda08e974a004f49e61f5d105284d20', 'hex'),
A_expected = ('61d5e490 f6f1b795 47b0704c 436f523d d0e560f0 c64115bb 72557ec4'
+'4352e890 3211c046 92272d8b 2d1a5358 a2cf1b6e 0bfcf99f 921530ec'
+'8e393561 79eae45e 42ba92ae aced8251 71e1e8b9 af6d9c03 e1327f44'
+'be087ef0 6530e69f 66615261 eef54073 ca11cf58 58f0edfd fe15efea'
+'b349ef5d 76988a36 72fac47b 0769447b').split(/\s/).join(''),
B_expected = ('bd0c6151 2c692c0c b6d041fa 01bb152d 4916a1e7 7af46ae1 05393011'
+'baf38964 dc46a067 0dd125b9 5a981652 236f99d9 b681cbf8 7837ec99'
+'6c6da044 53728610 d0c6ddb5 8b318885 d7d82c7f 8deb75ce 7bd4fbaa'
+'37089e6f 9c6059f3 88838e7a 00030b33 1eb76840 910440b1 b27aaeae'
+'eb4012b7 d7665238 a8e3fb00 4b117b58').split(/\s/).join(''),
u_expected = bigint('CE38B959 3487DA98 554ED47D 70A7AE5F 462EF019', 16),
S_expected = bigint('B0DC82BA BCF30674 AE450C02 87745E79 90A3381F 63B387AA F271A10D'
+'233861E3 59B48220 F7C4693C 9AE12B0A 6F67809F 0876E2D0 13800D6C'
+'41BB59B6 D5979B5C 00A172B4 A2A5903A 0BDCAF8A 709585EB 2AFAFA8F'
+'3499B200 210DCC1F 10EB3394 3CD67FC8 8A2F39A4 BE5BEC4E C0A3212D'
+'C346D7E4 74B29EDE 8A469FFE CA686E5A', 16);
u_expected = 'ce38b9593487da98554ed47d70a7ae5f462ef019',
S_expected = ('b0dc82ba bcf30674 ae450c02 87745e79 90a3381f 63b387aa f271a10d'
+'233861e3 59b48220 f7c4693c 9ae12b0a 6f67809f 0876e2d0 13800d6c'
+'41bb59b6 d5979b5c 00a172b4 a2a5903a 0bdcaf8a 709585eb 2afafa8f'
+'3499b200 210dcc1f 10eb3394 3cd67fc8 8a2f39a4 be5bec4e c0a3212d'
+'c346d7e4 74b29ede 8a469ffe ca686e5a').split(/\s/).join('');
function asHex(num) {
return num.toBuffer().toString('hex');
}
vows.describe('RFC 5054')

@@ -50,35 +51,45 @@

topic: function() {
return srp.getv(s, I, P, N, g, 'sha1');
return srp.computeVerifier(params, s, I, P);
},
"x": function() {
assert(x_expected.eq(srp.getx(s, I, P, 'sha1')));
var client = new srp.Client(params, s, I, P, a);
assert.equal(asHex(client._private.x_num), x_expected);
},
"V": function(v) {
assert(v_expected.eq(v));
assert.equal(v.toString('hex'), v_expected);
},
"k": function() {
assert(k_expected.eq(srp.getk(N, g, 'sha1')));
var client = new srp.Client(params, s, I, P, a);
assert.equal(asHex(client._private.k_num), k_expected);
},
"A": function() {
assert(A_expected.eq(srp.getA(g, a, N)));
var client = new srp.Client(params, s, I, P, a);
assert.equal(client.computeA().toString('hex'), A_expected);
},
"B": function(v) {
assert(B_expected.eq(srp.getB(v, g, b, N, 'sha1')));
var server = new srp.Server(params, v, b);
assert.equal(server.computeB().toString('hex'), B_expected);
},
"u": function() {
assert(u_expected.eq(srp.getu(A_expected, B_expected, N, 'sha1')));
var client = new srp.Client(params, s, I, P, a);
client.setB(Buffer(B_expected, 'hex'));
assert.equal(asHex(client._private.u_num), u_expected);
},
"S client": function() {
assert(S_expected.eq(srp.client_getS(s, I, P, N, g, a, B_expected, 'sha1')));
var client = new srp.Client(params, s, I, P, a);
client.setB(Buffer(B_expected, 'hex'));
assert.equal(client._private.S_buf.toString('hex'), S_expected);
},
"S server": function(v) {
assert(S_expected.eq(srp.server_getS(s, v, N, g, A_expected, b, 'sha1')));
var server = new srp.Server(params, v, b);
server.setA(Buffer(A_expected, 'hex'));
assert.equal(server._private.S_buf.toString('hex'), S_expected);
}

@@ -85,0 +96,0 @@ }

const vows = require('vows'),
assert = require('assert'),
bigint = require('bigint'),
params = require('../lib/params'),
srp = require('../lib/srp'),
s = new Buffer("salty"),
I = new Buffer("alice"),
P = new Buffer("password123"),
N = params[4096].N,
g = params[4096].g,
ALG_NAME = 'sha256';
params = srp.params[4096],
salt = new Buffer("salty"),
identity = new Buffer("alice"),
password = new Buffer("password123");
assert(params, "missing parameters");
var client, server;
var a, A;
var b, B;
var v;
var verifier;
var S_client, S_server;

@@ -21,62 +21,132 @@

.addBatch({
"getv": function() {
v = srp.getv(s, I, P, N, g, ALG_NAME);
assert(v.bitLength() > 0);
"create Verifier": function() {
verifier = srp.computeVerifier(params, salt, identity, password);
assert.equal(verifier.toString("hex"), "f0e47f50f5dead8db8d93a279e3b62d6ff50854b31fbd3474a886bef916261717e84dd4fb8b4d27feaa5146db7b1cbbc274fdf96a132b5029c2cd72527427a9b9809d5a4d018252928b4fc343bc17ce63c1859d5806f5466014fc361002d8890aeb4d6316ff37331fc2761be0144c91cdd8e00ed0138c0ce51534d1b9a9ba629d7be34d2742dd4097daabc9ecb7aaad89e53c342b038f1d2adae1f2410b7884a3e9a124c357e421bccd4524467e1922660e0a4460c5f7c38c0877b65f6e32f28296282a93fc11bbabb7bb69bf1b3f9391991d8a86dd05e15000b7e38ba38a536bb0bf59c808ec25e791b8944719488b8087df8bfd7ff20822997a53f6c86f3d45d004476d6303301376bb25a9f94b552cce5ed40de5dd7da8027d754fa5f66738c7e3fc4ef3e20d625df62cbe6e7adfc21e47880d8a6ada37e60370fd4d8fc82672a90c29f2e72f35652649d68348de6f36d0e435c8bd42dd00155d35d501becc0661b43e04cdb2da84ce92b8bf49935d73d75efcbd1176d7bbccc3cc4d4b5fefcc02d478614ee1681d2ff3c711a61a7686eb852ae06fb8227be21fb8802719b1271ba1c02b13bbf0a2c2e459d9bedcc8d1269f6a785cb4563aa791b38fb038269f63f58f47e9051499549789269cc7b8ec7026fc34ba73289c4af829d5a532e723967ce9b6c023ef0fd0cfe37f51f10f19463b6534159a09ddd2f51f3b30033");
},
"getx": function() {
assert(srp.getx(s, I, P, ALG_NAME).bitLength() > 0);
},
"with a": {
"create a and b": {
topic: function() {
var cb = this.callback;
srp.genKey(64, function(err, key) {
assert(err === null);
a = key;
cb(err, a);
srp.genKey(32, function(err, key) {
assert(err === null);
b = key;
cb();
});
});
},
},
"getA": function(err, a) {
assert(err === null);
"use a and b": function() {
client = new srp.Client(params, salt, identity, password, a);
A = srp.getA(g, a, N);
assert(A.bitLength() > 0);
// client produces A
A = client.computeA();
// create server
server = new srp.Server(params, verifier, b);
// server produces B
B = server.computeB();
// server accepts A
server.setA(A);
// client doesn't produce M1 too early
assert.throws(function(){client.computeM1();}, /incomplete protocol/);
// client accepts B
client.setB(B);
// client produces M1 now
client.computeM1();
// server likes client's M1
server.checkM1(client.computeM1());
// client and server agree on K
var client_K = client.computeK();
var server_K = server.computeK();
assert.equal(client_K.toString("hex"), server_K.toString("hex"));
},
"with b": {
topic: function() {
var cb = this.callback;
srp.genKey(32, function(err, key) {
b = key;
cb(err, b);
});
},
"getB": function(err, b) {
assert(err === null);
"constructor doesn't require 'new'": function() {
client = srp.Client(params, salt, identity, password, a);
B = srp.getB(v, g, b, N, ALG_NAME);
assert(B.bitLength() > 0);
},
// client produces A
A = client.computeA();
"getS": {
"by client": function() {
S_client = srp.client_getS(s, I, P, N, g, a, B, ALG_NAME);
assert(S_client.bitLength() > 0);
},
// create server
server = srp.Server(params, verifier, b);
"by server": function() {
S_server = srp.server_getS(s, v, N, g, A, b, ALG_NAME);
assert(S_server.bitLength() > 0);
},
// server produces B
B = server.computeB();
"by client and server are equal": function() {
assert(S_server.eq(S_client));
}
}
}
// server accepts A
server.setA(A);
// client doesn't produce M1 too early
assert.throws(function(){client.computeM1();}, /incomplete protocol/);
// client accepts B
client.setB(B);
// client produces M1 now
client.computeM1();
// server likes client's M1
server.checkM1(client.computeM1());
// client and server agree on K
var client_K = client.computeK();
var server_K = server.computeK();
assert.equal(client_K.toString("hex"), server_K.toString("hex"));
},
"server rejects wrong M1": function() {
var bad_client = new srp.Client(params, salt, identity, Buffer("bad"), a);
var server2 = new srp.Server(params, verifier, b);
bad_client.setB(server2.computeB());
assert.throws(function(){server.checkM1(bad_client.computeM1());},
/client did not use the same password/);
},
"server rejects bad A": function() {
// client's "A" must be 1..N-1 . Reject 0 and N and N+1. We should
// reject 2*N too, but our Buffer-length checks reject it before the
// number itself is examined.
var server2 = new srp.Server(params, verifier, b);
var Azero = new Buffer(params.N_length_bits/8);
Azero.fill(0);
var AN = params.N.toBuffer();
var AN1 = params.N.add(1).toBuffer();
assert.throws(function() {server2.setA(Azero);},
/invalid client-supplied 'A'/);
assert.throws(function() {server2.setA(AN);},
/invalid client-supplied 'A'/);
assert.throws(function() {server2.setA(AN1);},
/invalid client-supplied 'A'/);
},
"client rejects bad B": function() {
// server's "B" must be 1..N-1 . Reject 0 and N and N+1
var client2 = new srp.Client(params, salt, identity, password, a);
var Bzero = new Buffer(params.N_length_bits/8);
Bzero.fill(0, 0, params.N_length_bits/8);
var BN = params.N.toBuffer();
var BN1 = params.N.add(1).toBuffer();
assert.throws(function() {client2.setB(Bzero);},
/invalid server-supplied 'B'/);
assert.throws(function() {client2.setB(BN);},
/invalid server-supplied 'B'/);
assert.throws(function() {client2.setB(BN1);},
/invalid server-supplied 'B'/);
},
}
})
.export(module);
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc