跳转到主要内容

热门内容

今日:


总体:


最近浏览:


Chinese, Simplified

category

安全远程密码协议(SRP)是一种增强型密码认证密钥交换(PAKE)协议,专门设计用于绕过现有专利。1.

与所有PAKE协议一样,窃听者或中间人无法获得足够的信息,从而在没有与各方进行进一步交互的情况下,残酷地强行猜测密码或应用字典攻击。此外,作为增强的PAKE协议,服务器不存储密码等效数据。[2] 这意味着窃取服务器数据的攻击者不能伪装成客户端,除非他们首先对密码进行暴力搜索。

通俗地说,在SRP(或任何其他PAKE协议)身份验证过程中,一方(“客户端”或“用户”)向另一方(”服务器“)证明他们知道密码,而不发送密码本身或任何其他可以推导出密码的信息。密码永远不会离开客户端,服务器也不知道。

此外,服务器还需要知道密码(但不是密码本身),以便启动安全连接。这意味着服务器还可以向客户端进行身份验证,从而在不依赖用户解析复杂URL的情况下防止网络钓鱼。

SRP唯一经过数学证明的安全特性是,它相当于Diffie-Hellman对抗被动攻击者。[3] AuCPace[4]和OPAQUE等较新的PAKE提供了更强的保证。5.

概述


SRP协议具有许多理想的特性:它允许用户向服务器进行身份验证,它能够抵抗窃听者发起的字典攻击,并且不需要可信的第三方。它有效地将零知识密码证明从用户传递到服务器。在协议的修订版6中,每次连接尝试只能猜测一个密码。该协议的一个有趣特性是,即使它使用的一两个加密原语受到攻击,它仍然是安全的。SRP协议已经过多次修订,目前处于6a版本。

SRP协议以类似于Diffie-Hellman密钥交换的方式在双方之间创建了一个共享的大型私钥,客户端具有用户密码,服务器端具有从密码导出的密码验证器。共享公钥来自两个随机数,一个由客户端生成,另一个由服务器生成,这两个数字对于登录尝试是唯一的。在需要加密通信和身份验证的情况下,SRP协议比其他SSH协议更安全,比使用Diffie-Hellman密钥交换签名消息更快。与Kerberos不同,它也独立于第三方。

SRP协议版本3在RFC 2945中进行了描述。SRP版本6a也用于SSL/TLS[6](在TLS-SRP中)和其他标准(如EAP[7]和SAML)中的强密码身份验证,是IEEE 1363.2和ISO/IEC 11770-4的一部分。

协议


以下符号用于协议版本6的描述:

  • q and N = 2q + 1 are chosen such that both are prime (which makes q a Sophie Germain prime and N a safe prime). N must be large enough so that computing discrete logarithms modulo N is infeasible.
  • All arithmetic is performed in the ring of integers modulo N,
  • g is a generator of the multiplicative group

    .

  • H() is a hash function; e.g., SHA-256.
  • k is a parameter derived by both sides; in SRP-6, k = 3, while in SRP-6a it is derived from N and g : k = H(N, g). It is used to prevent a 2-for-1 guess when an active attacker impersonates the server.[8][9]
  • s is a salt.
  • I is an identifying username.
  • p is the user's password.
  • v is the host's password verifier, v = gx where at a minimum x = H(s, p). As x is only computed on the client it is free to choose a stronger algorithm. An implementation could choose to use x = H(s | I | p) without affecting any steps required of the host. The standard RFC2945 defines x = H(s | H ( I | ":" | p) ). Use of I within x avoids a malicious server from being able to learn if two users share the same password.
  • A and B are random one time ephemeral keys of the user and host respectively.
  • | (pipe) denotes concatenation.


所有其他变量都是根据这些定义的。

首先,为了与服务器Steve建立密码p,客户端Carol随机选择一个盐s,并计算x=H(s,p),v=gx。Steve将v和s(由I索引)存储为Carol的密码验证器和salt。Carol不得与任何人共享x,并且必须在这一步安全地删除它,因为它相当于明文密码p。这一步在系统用作Steve用户注册的一部分之前完成。请注意,盐s是共享和交换的,以便稍后协商会话密钥,因此值可以由任何一方选择,但由Carol完成,这样她就可以在一个注册请求中注册I、s和v。SRP中不包括注册请求的传输和身份验证。

然后,为了在以后执行密码验证,会出现以下交换协议:

  1. Carol → Steve: generate random value a; send I and A = ga
  2. Steve → Carol: generate random value b; send s and B = kv + gb
  3. Both: u = H(A, B)
  4. Carol: SCarol = (Bkgx)(a + ux) = (kv + gbkgx)(a + ux) = (kgxkgx + gb)(a + ux) = (gb)(a + ux)
  5. Carol: KCarol = H(SCarol)
  6. Steve: SSteve = (Avu)b = (gavu)b = [ga(gx)u]b = (ga + ux)b = (gb)(a + ux)
  7. Steve: KSteve = H(SSteve) = KCarol

     

现在双方都有一个共享的强会话密钥K。为了完成身份验证,他们需要向对方证明他们的密钥匹配。一种可能的方法如下:

  1. Carol → Steve: M1 = H[H(N) XOR H(g) | H(I) | s | A | B | KCarol]. Steve verifies M1.
  2. Steve → Carol: M2 = H(A | M1 | KSteve). Carol verifies M2.


此方法需要猜测更多的共享状态才能成功模拟,而不仅仅是密钥。虽然大部分附加状态是公开的,但私有信息可以安全地添加到哈希函数的输入中,就像服务器私钥一样。[需要澄清]

或者,在仅验证密码的情况下,可以跳过K的计算,并用以下公式验证共享S:

  1. Carol → Steve: M1 = H(A | B | SCarol). Steve verifies M1.
  2. Steve → Carol: M2 = H(A | M1 | SSteve). Carol verifies M2.


当使用SRP协商将在协商后立即使用的共享密钥K时,很容易跳过M1和M2的验证步骤。服务器将拒绝来自客户端的第一个无法解密的请求。然而,正如下面的实施陷阱部分所示,这可能是危险的。

双方还采取了以下保障措施:

  1. Carol will abort if she receives B = 0 (mod N) or u = 0.
  2. Steve will abort if he receives A (mod N) = 0.
  3. Carol must show her proof of K (or S) first. If Steve detects that Carol's proof is incorrect, he must abort without showing his own proof of K (or S)


Python示例代码

"""
An example SRP authentication

WARNING: Do not use for real cryptographic purposes beyond testing.
WARNING: This below code misses important safeguards. It does not check A, B, and U are not zero.

based on http://srp.stanford.edu/design.html
"""
import hashlib
import random

# Note: str converts as is, str([1,2,3,4]) will convert to "[1,2,3,4]"
def H(*args) -> int:
    """A one-way hash function."""
    a = ":".join(str(a) for a in args)
    return int(hashlib.sha256(a.encode("utf-8")).hexdigest(), 16)

def cryptrand(n: int = 1024):
    return random.SystemRandom().getrandbits(n) % N

# A large safe prime (N = 2q+1, where q is prime)
# All arithmetic is done modulo N
# (generated using "openssl dhparam -text 1024")
N = """00:c0:37:c3:75:88:b4:32:98:87:e6:1c:2d:a3:32:
       4b:1b:a4:b8:1a:63:f9:74:8f:ed:2d:8a:41:0c:2f:
       c2:1b:12:32:f0:d3:bf:a0:24:27:6c:fd:88:44:81:
       97:aa:e4:86:a6:3b:fc:a7:b8:bf:77:54:df:b3:27:
       c7:20:1f:6f:d1:7f:d7:fd:74:15:8b:d3:1c:e7:72:
       c9:f5:f8:ab:58:45:48:a9:9a:75:9b:5a:2c:05:32:
       16:2b:7b:62:18:e8:f1:42:bc:e2:c3:0d:77:84:68:
       9a:48:3e:09:5e:70:16:18:43:79:13:a8:c3:9c:3d:
       d0:d4:ca:3c:50:0b:88:5f:e3"""
     
N = int("".join(N.split()).replace(":", ""), 16)
g = 2  # A generator modulo N

k = H(N, g) # Multiplier parameter (k=3 in legacy SRP-6)

F = '#0x' # Format specifier

print("#. H, N, g, and k are known beforehand to both client and server:")
print(f'{H = }\n{N = :{F}}\n{g = :{F}}\n{k = :{F}}')

print("\n0. server stores (I, s, v) in its password database")

# The server must first generate the password verifier
I = "person"        # Username
p = "password1234"  # Password
s = cryptrand(64)   # Salt for the user
x = H(s, I, p)      # Private key
v = pow(g, x, N)    # Password verifier

print(f'{I = }\n{p = }\n{s = :{F}}\n{x = :{F}}\n{v = :{F}}')

# 0. server stores(I, s, v) in its password database
# I = 'person'
# p = 'password1234'
# s = 0x67bc8932cfd26a49
# x = 0x98a4bce8dde877762a90222f1a1161eba9248590a47eb83aa9e5bd7ecda5368d
# v = 0xa7e2038e675d577ac0f318999cab67bba7ec2daf45d2d09f7911b1b78d2fc7f963cd0ac8f17851e0516f059e453672c3b70fce
cf5f6843180b271abdd01f552ccda7b24fe4719336409cbc1352f8517be651b8935cc0b74ff2819fa07a3f031537d4cfd9f8df
7b788a5f2f88e1cd4106b35c38b3d7205a

# <demo> --- stop ---

print("\n1. client sends username I and public ephemeral value A to the server")
a = cryptrand()
A = pow(g, a, N)
print(f"{I = }\n{A = :{F}}")  # client->server (I, A)

# 1. client sends username I and public ephemeral value A to the server
# I = 'person'
# A = 0x678556a7e76581e051af656e8cee57ae46df43f1fce790f7750a3ec5308a85da4ec4051e5cb74d3e463685ee975a2747cf49035be
67c931b56e793f23ea3524af8909dcfbc8675d872361025bf884778587ac49454a57c53a011ac2be2839bfb51bf7847a49a483aba870dc7a8
b467a81cec91b8ae7813

# <demo> --- stop ---

print("\n2. server sends user's salt s and public ephemeral value B to client")
b = cryptrand()
B = (k * v + pow(g, b, N)) % N
print(f"{s = :{F}}\n{B = :{F}}")  # server->client (s, B)

# 2. server sends user's salt s and public ephemeral value B to client
# s = 0x67bc8932cfd26a49
# B = 0xb615a0a5ea6abf138077bbd869f6a8da37dfc0b7e06a9f5fac5c1e4109c6302cb3e94dcc2cc76da7b3d87d7e9b68a1db998ab239c
fde609f3f7a1ece4a491ce3d9a665c20cf4e4f06730daaa8f52ed61e45bbb67cdc337bf648027ffa7f0f215d5ebe43f9f51832518f11422
66aae0dfa960e0082b5154


# <demo> --- stop ---

print("\n3. client and server calculate the random scrambling parameter")
u = H(A, B)  # Random scrambling parameter
print(f"{u = :{F}}")

# 3. client and server calculate the random scrambling parameter
# u = 0x796b07e354c04f672af8b76a46560655086355a9bbce11361f01b45d991c0c52

# <demo> --- stop ---

print("\n4. client computes session key")
x = H(s, I, p)
S_c = pow(B - k * pow(g, x, N), a + u * x, N)
K_c = H(S_c)
print(f"{S_c = :{F}}\n{K_c = :{F}}")

# 4. client computes session key
# S_c = 0x699170aff6e9f08ed09a1dff432bf0605b8bcba05aadcaeea665757d06dbda4348e211d16c10ef4678585bcb2809a
83c62b6c19d97901274ddaf
d4075f90604c06baf036af587af8540342b47867eaa22b9ca5e35ac14c8e85a0c4e623bd855828dffd513cea4d829c40
7137a0dd81ab4cde8a904c45cc
# K_c = 0x43f8df6e1d2ba762948c8316db5bf03a7af49391742f5f51029630711c1671e

# <demo> --- stop ---

print("\n5. server computes session key")
S_s = pow(A * pow(v, u, N), b, N)
K_s = H(S_s)
print(f"{S_s = :{F}}\n{K_s = :{F}}")

# 5. server computes session key
# S_s = 0x699170aff6e9f08ed09a1dff432bf0605b8bcba05aadcaeea665757d06dbda4348e211d16c10ef4678585bcb2809
a83c62b6c19d97901
274ddafd4075f90604c06baf036af587af8540342b47867eaa22b9ca5e35ac14c8e85a0c4e623bd855828dffd513cea4d829c
407137a0dd81ab4cde8a904c45cc
# K_s = 0x43f8df6e1d2ba762948c8316db5bf03a7af49391742f5f51029630711c1671e

# <demo> --- stop ---

print("\n6. client sends proof of session key to server")
M_c = H(H(N) ^ H(g), H(I), s, A, B, K_c)
print(f"{M_c = :{F}}")
# client->server (M_c) ; server verifies M_c

# 6. client sends proof of session key to server
# M_c = 0x75500df4ea36e06406ac1f8a8241429b8e90a8cba3adda3405c07f19ea3101e8

# <demo> --- stop ---

print("\n7. server sends proof of session key to client")
M_s = H(A, M_c, K_s)
print(f"{M_s = :{F}}")
# server->client (M_s) ;  client verifies M_s

# 7. server sends proof of session key to client
# M_s = 0x182ed24d1ad2fb55d2268c46b42435d1ef02e0fc49f647c03dab8b2a48b0bd3d

 

实施陷阱


在没有密钥验证的情况下,使用服务器优先消息进行离线暴力攻击


如果服务器在不等待客户端验证的情况下发送加密消息,则攻击者能够发起类似于哈希破解的离线暴力攻击。如果服务器在第二个数据包中与盐和B一起发送加密消息,或者如果跳过密钥验证并且服务器(而不是客户端)发送第一个加密消息,则可能会发生这种情况。这很诱人,因为在第一个数据包之后,服务器拥有计算共享密钥K的所有信息。

攻击过程如下:

  1. Carol → Steve: generate random value a; send I and A = ga
  2. Steve: u = H(A, B); S=Avu; K=H(S)
  3. Steve: generate message m and encrypts it to produce c=ENC(K,m)
  4. Steve → Carol: generate random value b; send s, B = kv + gb and c


Carol不知道x或v。但给定任何密码p,她都可以计算:

  • xp = H(salt, p)
  • Sp = (B - kgxp)(a + uxp)
  • Kp = H(Sp)


如果p是预期的密码,则Kp是Steve将使用的密钥。计算Kp所需的所有值要么由Carol控制,要么从Steve的第一个数据包中已知。Carol现在可以尝试猜测密码,生成相应的密钥,并尝试解密Steve的加密消息c以验证密钥。由于协议消息往往是结构化的,因此假设识别c是否被正确解密很容易。这允许脱机恢复密码。

如果Steve在发送加密消息之前等待Carol证明她能够计算出正确的密钥,那么这种攻击是不可能的。SRP的正确实现不受此攻击的影响,因为攻击者将无法通过密钥验证步骤。

基于时间攻击的离线暴力


2021年,Daniel De Almeida Braga、Pierre Alain Fouque和Mohamed Sabt发表了《PARASITE》,[10]他们在论文中展示了对网络定时攻击的实际利用。这利用了大数模幂运算的非常数实现,尤其影响了OpenSSL。

实施

 

历史


SRP项目始于1997年。[11]修复SRP-1中安全漏洞的两种不同方法产生了SRP-2和SRP-3。[12]SRP-3于1998年在一次会议上首次发表。[13] RFC 2945于2000年发布,其中描述了带有SHA1的SRP-3。[14]SRP-6于2002年发布,修复了“二对一”猜测和消息排序攻击。[8]SRP-6a出现在2005年2.1.0版本的官方“libsrp”中。[15]SRP-6a在标准中如下:
ISO/IEC 11770-4:2006“密钥协商机制2”(称该方法为“SRP-6,但k计算为6a)
2007年的RFC 5054 TLS-SRP(再次称为“SRP-6”,但在勘误表中进行了更正[16])
IEEE标准1363.2-2008“DLAPKAS-SRP6”(再次称为“SRP-6”)[17]
IEEE 1363.2还包括对“SRP5”的描述,这是一种用椭圆曲线代替离散对数的变体,由Yongge Wang于2001年提出。[18]它还描述了RFC 2945中的SRP-3。

See also

References

  1. ^ "What is SRP?". Stanford University.
  2. ^ Sherman, Alan T.; Lanus, Erin; Liskov, Moses; Zieglar, Edward; Chang, Richard; Golaszewski, Enis; Wnuk-Fink, Ryan; Bonyadi, Cyrus J.; Yaksetig, Mario (2020), Nigam, Vivek; Ban Kirigin, Tajana; Talcott, Carolyn; Guttman, Joshua (eds.), "Formal Methods Analysis of the Secure Remote Password Protocol", Logic, Language, and Security: Essays Dedicated to Andre Scedrov on the Occasion of His 65th Birthday, Lecture Notes in Computer Science, Cham: Springer International Publishing, pp. 103–126, arXiv:2003.07421, doi:10.1007/978-3-030-62077-6_9, ISBN 978-3-030-62077-6
  3. ^ Green, Matthew (18 October 2018). "Should you use SRP?". A Few Thoughts on Cryptographic Engineering. NB: source refers to SRP-6 as SRPv4 for reason unknown.
  4. ^ Haase, Björn (22 January 2023). "(strong) AuCPace, an augmented PAKE [draft-haase-aucpace-07]". Internet Engineering Task Force. Retrieved 10 June 2023.
  5. ^ Stanislaw Jarecki; Hugo Krawczyk; Jiayu Xu. OPAQUE: An Asymmetric PAKE Protoco lSecure Against Pre-Computation Attacks (PDF). Eurocrypt 2018.
  6. ^ Taylor, David; Tom Wu; Nikos Mavrogiannopoulos; Trevor Perrin (November 2007). "Using the Secure Remote Password (SRP) Protocol for TLS Authentication". RFC 5054
  7. ^ Carlson, James; Bernard Aboba; Henry Haverinen (July 2001). "EAP SRP-SHA1 Authentication Protocol". IETF. Draft.
  8. ^ Jump up to:a b Wu, Tom (October 29, 2002). SRP-6: Improvements and Refinements to the Secure Remote Password Protocol (Technical report).
  9. ^ "SRP Protocol Design".
  10. ^ "PARASITE: PAssword Recovery Attack against Srp Implementations in ThE wild". Retrieved 8 November 2023.
  11. ^ "SRP: About the Project". srp.stanford.edu.
  12. ^ "SRP-2: Design Specifications". srp.stanford.edu.
  13. ^ Wu, T., "The Secure Remote Password Protocol", Proceedings of the 1998 Internet Society Network and Distributed System Security Symposium pp. 97-111, March 1998.
  14. ^ "SRP: Design Specifications". srp.stanford.edu.
  15. ^ CHANGES file in srp-2.1.2.tar.gz, available from http://srp.stanford.edu/download.html
  16. ^ Wang, Mingye. "RFC Errata Report #7538". RFC Editor. Retrieved 15 October 2023.
  17. ^ IEEE 1363.2-2008: IEEE Standard Specification for Password-Based Public-Key Cryptographic Techniques
  18. ^ Wang, Y., "IEEE P1363.2 Submission / D2001-06-21," [P1363.2-ecsrp-06-21.doc] A contribution by Yongge Wang for P1363.2 giving an elliptic curve version of the SRP protocol, June 21, 2001.
  • Official website
  • SRP License—BSD like open source.
  • US6539479 - SRP Patent (Expired on May 12, 2015 due to failure to pay maintenance fees (according to Google Patents). Originally set to expire in July 2018).

Manual pages

RFCs

  • RFC 2944 - Telnet Authentication: SRP
  • RFC 2945 - The SRP Authentication and Key Exchange System (version 3)
  • RFC 3720 - Internet Small Computer Systems Interface (iSCSI)
  • RFC 3723 - Securing Block Storage Protocols over IP
  • RFC 3669 - Guidelines for Working Groups on Intellectual Property Issues
  • RFC 5054 - Using the Secure Remote Password (SRP) Protocol for TLS Authentication
本文地址
最后修改
星期二, 一月 7, 2025 - 11:11
Article