Điểm:2

Tại sao hầu hết thời gian có một chút không khớp trong các khóa riêng X25519 tùy thuộc vào các chức năng được sử dụng, nhưng các khóa chung luôn khớp (cùng một hạt giống cho cả hai)?

lá cờ cn
mkl

Tôi đang cố gắng xoay sở để đi từ một hạt giống đến một Ký chính, và cũng có được một Khóa riêng (khóa mã hóa). Tôi đang sử dụng NaCl/libsodium.

Tôi đã tạo mã bên dưới và kết quả thật thú vị. hóa ra pk1.private_keypk2.private_key phù hợp với khoảng 3% thời gian. Tuy nhiên, khóa công khai khớp 100%, tất cả đều được tạo bắt đầu bằng cùng một khóa hạt giống. Chuyện gì đang xảy ra ở đây?

  • tôi có được pk1 bằng cách sử dụng PrivateKey.from_seed(hạt giống)

  • tôi có được pk2 bằng cách sử dụng SigningKey(seed).to_curve25519_private_key()

Ví dụ về sự không phù hợp (chúng gần giống nhau nhưng không bằng nhau):

# byte đầu tiên không khớp bởi 0x01
hạt giống: f8d9e54a23971beebf2552c1a50ade6150cd051321398394f515e8d4b1ba0404
priv1: c1fd4612ee8ef24d295210a277e196e6bb4a9ae6b93f98d93f197860fe5dc048
priv2: c0fd4612ee8ef24d295210a277e196e6bb4a9ae6b93f98d93f197860fe5dc048

# byte đầu tiên không khớp bởi 0x03
hạt giống: d612a66f92ee2f42ab1f7ea9a712a47c815843d21fc988b1d202459f235b6410
priv1: f33d5e80bb556333e2961c9868b1dc7e548836ee56808689ca022f1a19fe86bb
priv2: f03d5e80bb556333e2961c9868b1dc7e548836ee56808689ca022f1a19fe867b

# Byte đầu tiên không khớp với 0x01, byte cuối cùng không khớp với 0x40
hạt giống: 10b7e1c66cf08005a22289158a088e028160f892dc6c20d43025be4690aaed85
priv1: 194898f65d117579d50e80a9b7e07bd048bfd1300d55561dac9dfaed4ef02109
priv2: 184898f65d117579d50e80a9b7e07bd048bfd1300d55561dac9dfaed4ef02149
từ nacl.signing nhập SigningKey
từ nacl.public nhập PrivateKey, PublicKey, Box, SealedBox
từ nacl.bindings nhập crypto_sign_SEEDBYTES
từ nacl.utils nhập StringFixer, ngẫu nhiên

chạy def (gỡ lỗi = Sai):
    hạt giống = ngẫu nhiên (crypto_sign_SEEDBYTES)
    pk1 = PrivateKey.from_seed(hạt giống)
    pk2 = SigningKey(seed).to_curve25519_private_key()
    nếu gỡ lỗi:
        in('hạt giống: ', hạt giống.hex()) 
        in('priv1: ', pk1._private_key.hex())
        in('priv2: ', pk2._private_key.hex())
        in('pub1: ', byte(pk1.public_key).hex())
        in('pub2: ', byte(pk2.public_key).hex())
    trả lại hạt giống, pk1, pk2

chạy = 10000
private_key_match = 0
public_key_match = 0
both_match = 0

cho tôi trong phạm vi (chạy):
    nếu tôi % 500 == 0:
        in(i, 'của', chạy)
    hạt giống, pk1, pk2 = chạy()
    x = pk1._private_key == pk2._private_key
    y = byte(pk1.public_key) == byte(pk2.public_key)
    nếu x:
        private_key_match += 1
    nếu bạn:
        public_key_match += 1
    nếu x và y:
        both_match += 1

print('khớp khóa cá nhân:', private_key_match)
print('khớp khóa công khai: ', public_key_match)
print('cả hai khớp: ', both_match)
Maarten Bodewes avatar
lá cờ in
Khóa riêng phải có một vài bit được đặt thành các giá trị cụ thể, nếu chúng đã được đặt một cách tình cờ thì bạn sẽ nhận được những gì bạn nhận được.
lá cờ cn
mkl
@MaartenBodewes, tôi không chắc là mình làm theo, khóa riêng không đại diện cho một số nguyên được sử dụng trong tính toán khóa chung cũng như giải mã. Tại sao một số bit sẽ không quan trọng? Có thông số kỹ thuật nào tôi đang thiếu không?
Maarten Bodewes avatar
lá cờ in
Ugh, tôi phải tra cứu các phương trình cho điều đó, tuy nhiên tôi tự hỏi liệu sự khác biệt có phải là khi áp dụng mặt nạ bit hay không. Tôi đã hy vọng nhận được sự giúp đỡ từ các nhà mật mã học đồng nghiệp của tôi ở đây.
Điểm:2
lá cờ cn

'curve25519' (ban đầu Bernstein gọi nó, bây giờ được đổi tên thành X25519 hoặc XDH25519 cho rõ ràng vì giống nhau đường cong ở dạng khác được sử dụng cho Ed25519[ph]) yêu cầu khóa riêng (hệ số nhân) phải là bội số của 8 để tránh các cuộc tấn công của nhóm con nhỏ và theo quy ước được biểu diễn bằng little-endian nên 3 bit thấp của byte đầu tiên buộc phải 0.

X25519 cũng yêu cầu bit cao bằng 0 (vì trường cơ bản của nó chỉ khoảng $2^{255}$) và Bernstein chỉ định bit tiếp theo đến cao là 1 (để chặn 'tối ưu hóa' cho phép tấn công theo thời gian); những điều này ảnh hưởng đến Cuối cùng byte ở dạng little-endian mà dường như bạn không nhận thấy trong các ví dụ của mình cũng thay đổi bb - 7b và 09 - 49.

Hai (hoặc ba) kẹp này được thực hiện cùng nhau sẽ thay đổi tất cả giá trị được chọn ngẫu nhiên trừ (100/32)% thời gian, đủ gần 3% cho công việc của chính phủ.

Ed25519 thực sự có cùng nhu cầu về số nhân riêng của nó là bội số của 8, nhưng nó không sử dụng khóa riêng trực tiếp cho số nhân; thay vào đó, nó chạy khóa riêng thông qua hàm băm để mở rộng và sử dụng cho cả hệ số và giá trị bí mật làm mù thông báo và chỉ kẹp bên trong phần hệ số mà không sửa đổi những gì người dùng coi là khóa riêng.

bịp bợm Tại sao 3 bit thấp hơn của khóa bí mật Curve25519/ed25519 bị xóa trong quá trình tạo?
Cấu trúc phím Curve25519
và xem/so sánh https://datatracker.ietf.org/doc/html/rfc7748#page-8
so với https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5 .

knaccc avatar
lá cờ es
Lưu ý rằng không nhất thiết phải có khóa riêng trên một trong hai biến thể của đường cong 25519 là bội số của 8. Một số triển khai chữ ký hoặc DH nhất định có thể thực hiện việc này, nhưng đó chỉ là một cách để ngăn chặn một cuộc tấn công nhóm nhỏ. Bạn cũng có thể ngăn chặn cuộc tấn công bằng cách nhân điểm EC với thứ tự nhóm và kiểm tra xem kết quả có phải là điểm ở vô cực hay không. Điều này cũng sẽ xác minh rằng điểm EC nằm trong nhóm con lớn hơn chính xác, ngăn chặn các loại tấn công khác, chẳng hạn như tấn công tính duy nhất của hình ảnh khóa chữ ký vòng có thể liên kết.
lá cờ cn
mkl
@dave_thompson_085, điều đó cực kỳ hữu ích, cảm ơn bạn.Vì vậy, có vẻ như một trong các chức năng được triển khai không đầy đủ? Mặc dù một trong hai khóa riêng tạo ra cùng một khóa chung (tôi cho rằng một số kiểm tra/dọn dẹp xảy ra khi tạo khóa pub)
dave_thompson_085 avatar
lá cờ cn
@miketery Không có gì là không hoàn chỉnh. Như tôi đã nói, các sơ đồ được định nghĩa khác nhau; X25519 yêu cầu kẹp vào khóa riêng được nhìn thấy bên ngoài, trong khi Ed25519 áp dụng nó bên trong để khóa riêng được nhìn thấy không bị kẹp nhưng phép nhân đường cong elip bên trong thì có.
Điểm:2
lá cờ cn

Về mặt toán học, một đường cong25519 khóa riêng là một phần tử của $\mathbb{F}_{2^{255}-19}$, tức là một modulo số nguyên $2^{255}-19$. Điều này có thể được biểu diễn một cách tự nhiên dưới dạng một số nguyên giữa $0$$2^{255}-19-1$, bản thân nó có thể được biểu diễn bằng 255 bit. Vì các máy tính thực tế hoạt động với các byte 8 bit, nên biểu diễn thực tế nhỏ nhất là một chuỗi 32 byte.

Có một định dạng chuẩn để biểu diễn các khóa riêng Curve25519, được mô tả trong RFC 7748 §5. Định dạng này mã hóa số nguyên giữa $0$$2^{255}-19-1$ dưới dạng chuỗi 32 byte (256 bit) theo thứ tự cuối nhỏ.

Chuỗi 32 byte có thể biểu thị các số trong phạm vi $[0,2^{256}-1]$, lớn hơn $[0,2^{255}-19-1]$. Ngoài ra, vì nhiều lý do, không phải tất cả các số trong dải $[0,2^{255}-19-1]$ tốt (xem Cấu trúc phím Curve25519“May the Fourth Be With You: A Microarchitectural Side Channel Attack on Some Real-World Applications of Curve25519â by Genkin et al). Các ràng buộc là:

  • Số phải nằm giữa $2^{254}$$2^{255}-19$, vì vậy hai bit quan trọng nhất của số 256 bit phải là 0 và 1.
  • Số phải là bội số của 8, vì vậy ba bit có nghĩa nhỏ nhất phải bằng 0.

RFC 7748 §5 chỉ định rằng khi tạo khóa riêng, người ta phải lấy một chuỗi 32 byte ngẫu nhiên (hoặc giả ngẫu nhiên, tùy từng trường hợp) và buộc năm bit được đề cập ở trên thành giá trị bắt buộc của chúng. Việc triển khai Curve25519 lấy khóa riêng tư làm đầu vào ở dạng chuỗi 32 byte phải áp dụng mặt nạ này trước khi bắt đầu thực hiện tính toán trên số mà khóa đại diện.

nacl.public.PrivateKey.from_seed trả về chuỗi 32 byte thô. nacl.signing.SigningKey(hạt giống) thực hiện mặt nạ, vì vậy to_curve25519_private_key xuất giá trị ở dạng chính tắc, được che giấu.

Mặt nạ liên quan đến 5 bit, do đó, với một hạt giống ngẫu nhiên, có một $1/2^5 = 1/32 \khoảng 3\%$ cơ hội là nó đã có giá trị chính xác cho 5 bit đó.

lá cờ cn
mkl
Câu trả lời tuyệt vời, cảm ơn bạn!

Đăng câu trả lời

Hầu hết mọi người không hiểu rằng việc đặt nhiều câu hỏi sẽ mở ra cơ hội học hỏi và cải thiện mối quan hệ giữa các cá nhân. Ví dụ, trong các nghiên cứu của Alison, mặc dù mọi người có thể nhớ chính xác có bao nhiêu câu hỏi đã được đặt ra trong các cuộc trò chuyện của họ, nhưng họ không trực giác nhận ra mối liên hệ giữa câu hỏi và sự yêu thích. Qua bốn nghiên cứu, trong đó những người tham gia tự tham gia vào các cuộc trò chuyện hoặc đọc bản ghi lại các cuộc trò chuyện của người khác, mọi người có xu hướng không nhận ra rằng việc đặt câu hỏi sẽ ảnh hưởng—hoặc đã ảnh hưởng—mức độ thân thiện giữa những người đối thoại.