diff options
author | joe <joe@jerkface.net> | 2017-11-03 23:02:31 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-11-03 23:02:31 -0400 |
commit | b3f55f54aa7eb2c7cc62979781b4dd8b3d359f89 (patch) | |
tree | fd15341f7d0e6e74102a4656716ee121eaa8401e | |
parent | b514e562e0d77b9adb8ca5c75289204013de2968 (diff) |
Fixed bug in decodeSecret/encodeSecret.
-rw-r--r-- | src/Crypto/Tox.hs | 65 |
1 files changed, 50 insertions, 15 deletions
diff --git a/src/Crypto/Tox.hs b/src/Crypto/Tox.hs index 9f86f6a4..307a5db5 100644 --- a/src/Crypto/Tox.hs +++ b/src/Crypto/Tox.hs | |||
@@ -428,27 +428,62 @@ getPublicKey = throwCryptoError . publicKey <$> S.getBytes 32 | |||
428 | putPublicKey :: PublicKey -> S.Put | 428 | putPublicKey :: PublicKey -> S.Put |
429 | putPublicKey bs = S.putByteString $ BA.convert bs | 429 | putPublicKey bs = S.putByteString $ BA.convert bs |
430 | 430 | ||
431 | -- 32 bytes -> 42 base64 digits. | ||
432 | -- | ||
431 | encodeSecret :: SecretKey -> Maybe C8.ByteString | 433 | encodeSecret :: SecretKey -> Maybe C8.ByteString |
432 | encodeSecret k = do | 434 | encodeSecret k = do |
433 | (a,bs) <- BA.uncons (BA.convert k) | 435 | (a,bs) <- BA.uncons (BA.convert k) |
436 | -- Bytes | ||
437 | -- 1 31 | ||
438 | -- a | bs | ||
434 | (cs,c) <- unsnoc bs | 439 | (cs,c) <- unsnoc bs |
435 | let a' = shiftR a 1 .|. (shiftR c 4 .&. 0x03) | 440 | -- Bytes |
441 | -- 1 30 1 | ||
442 | -- a | cs | c | ||
443 | -- | ||
444 | -- Based on the following pasted from the generateSecretKey function: | ||
445 | -- | ||
446 | -- tweakToSecretKey :: ScrubbedBytes -> SecretKey | ||
447 | -- tweakToSecretKey bin = SecretKey $ B.copyAndFreeze bin $ \inp -> do | ||
448 | -- modifyByte inp 0 (\e0 -> e0 .&. 0xf8) | ||
449 | -- modifyByte inp 31 (\e31 -> (e31 .&. 0x7f) .|. 0x40) | ||
450 | -- | ||
451 | -- We know the following holds: | ||
452 | -- a == a .&. 0xf8 | ||
453 | -- c == (c .&. 0x7f) .|. 0x40 | ||
454 | -- | ||
455 | -- Therefore, there are 5 reserved bits: | ||
456 | -- a := aaaa a000 | ||
457 | -- c := 01dd cccc | ||
458 | -- | ||
459 | -- That gives us 256 - 5 = 251 bits to encode. | ||
460 | -- 42 * 6 = 252 | ||
461 | -- | ||
462 | let -- We'll reserve the first bit as zero so that the encoded | ||
463 | -- key starts with a digit between A and f. Other digits will be | ||
464 | -- arbitrary. | ||
465 | -- | ||
466 | -- The middle 30 bytes will be encoded as is from the source byte | ||
467 | -- string (cs). It remains to compute the first (a') and last (c') | ||
468 | -- bytes. | ||
469 | xs = Base64.encode $ a' `BA.cons` cs `BA.snoc` c' | ||
470 | -- a' := 0aaaaadd | ||
471 | a' = shiftR a 1 .|. (shiftR c 4 .&. 0x03) | ||
472 | -- c' := cccc0000 | ||
436 | c' = shiftL c 4 | 473 | c' = shiftL c 4 |
437 | xs = Base64.encode $ cs `BA.snoc` a' `BA.snoc` c' | 474 | return $ BA.take 42 xs |
438 | (ys,ds) = BA.splitAt 40 xs | ||
439 | return $ BA.index ds 0 `BA.cons` ys `BA.snoc` BA.index ds 1 | ||
440 | 475 | ||
476 | -- 42 base64 digits. First digit should be between A and f. The rest are | ||
477 | -- arbitrary. | ||
441 | decodeSecret :: C8.ByteString -> Maybe SecretKey | 478 | decodeSecret :: C8.ByteString -> Maybe SecretKey |
479 | decodeSecret k64 | B.length k64 < 42 = Nothing | ||
442 | decodeSecret k64 = do | 480 | decodeSecret k64 = do |
443 | (ds0,ysds1) <- BA.uncons k64 | 481 | xs <- either (const Nothing) Just $ Base64.decode $ B.append k64 "A=" |
444 | (ys,ds1) <- unsnoc ysds1 | 482 | (a',ds) <- B.uncons $ B.take 32 xs |
445 | let k64' = B.append ys (BA.cons ds0 (BA.cons ds1 "A=")) | 483 | (cs,c') <- B.unsnoc ds |
446 | k <- either (const Nothing) Just $ Base64.decode k64' | 484 | let c = 0x40 .|. shiftR c' 4 .|. ( 0x30 .&. shiftL a' 4) |
447 | (csa,c') <- unsnoc k | 485 | a = 0xf8 .&. shiftL a' 1 |
448 | (cs,a') <- unsnoc csa | 486 | case secretKey $ B.cons a cs `B.snoc` c of |
449 | let a = shiftL (a' .&. 0x7c) 1 | ||
450 | c = shiftR c' 4 .|. (shiftL a' 4 .&. 0x30) .|. 0x40 | ||
451 | let r = a `BA.cons` (cs `BA.snoc` c) | ||
452 | case secretKey r of | ||
453 | CryptoPassed x -> Just x | 487 | CryptoPassed x -> Just x |
454 | _ -> Nothing | 488 | _ -> Nothing |
489 | |||