diff options
Diffstat (limited to 'Data/OpenPGP.hs')
-rw-r--r-- | Data/OpenPGP.hs | 75 |
1 files changed, 51 insertions, 24 deletions
diff --git a/Data/OpenPGP.hs b/Data/OpenPGP.hs index 35298c8..4627d4e 100644 --- a/Data/OpenPGP.hs +++ b/Data/OpenPGP.hs | |||
@@ -64,7 +64,9 @@ module Data.OpenPGP ( | |||
64 | signature_issuer, | 64 | signature_issuer, |
65 | public_key_fields, | 65 | public_key_fields, |
66 | secret_key_fields, | 66 | secret_key_fields, |
67 | eccOID | 67 | eccOID, |
68 | encode_public_key_material, | ||
69 | decode_public_key_material | ||
68 | ) where | 70 | ) where |
69 | 71 | ||
70 | import Control.Applicative | 72 | import Control.Applicative |
@@ -80,6 +82,7 @@ import Data.Maybe | |||
80 | import Data.Monoid | 82 | import Data.Monoid |
81 | import Data.OpenPGP.Internal | 83 | import Data.OpenPGP.Internal |
82 | import Data.Word | 84 | import Data.Word |
85 | import GHC.Stack | ||
83 | import Numeric | 86 | import Numeric |
84 | 87 | ||
85 | #ifdef CEREAL | 88 | #ifdef CEREAL |
@@ -345,8 +348,8 @@ public_key_fields RSA_S = public_key_fields RSA | |||
345 | public_key_fields ELGAMAL = ['p', 'g', 'y'] | 348 | public_key_fields ELGAMAL = ['p', 'g', 'y'] |
346 | public_key_fields DSA = ['p', 'q', 'g', 'y'] | 349 | public_key_fields DSA = ['p', 'q', 'g', 'y'] |
347 | public_key_fields ECDSA = ['c','l','x', 'y', 'f'] | 350 | public_key_fields ECDSA = ['c','l','x', 'y', 'f'] |
348 | public_key_fields Ed25519 = ['c','l','x', 'y', 'f'] | 351 | public_key_fields Ed25519 = ['c','l','x', 'y', 'n', 'f'] |
349 | public_key_fields ECC = ['c','l','x', 'y', 'f'] | 352 | public_key_fields ECC = ['c','l','x', 'y', 'n', 'f', 'e'] |
350 | public_key_fields alg = error ("Unknown key fields for "++show alg) -- Nothing in the spec. Maybe empty | 353 | public_key_fields alg = error ("Unknown key fields for "++show alg) -- Nothing in the spec. Maybe empty |
351 | 354 | ||
352 | -- http://tools.ietf.org/html/rfc4880#section-5.5.3 | 355 | -- http://tools.ietf.org/html/rfc4880#section-5.5.3 |
@@ -359,8 +362,10 @@ secret_key_fields DSA = ['x'] | |||
359 | secret_key_fields ECDSA = ['d'] | 362 | secret_key_fields ECDSA = ['d'] |
360 | secret_key_fields alg = error ("Unkown secret fields for "++show alg) -- Nothing in the spec. Maybe empty | 363 | secret_key_fields alg = error ("Unkown secret fields for "++show alg) -- Nothing in the spec. Maybe empty |
361 | 364 | ||
362 | (!) :: (Eq k) => [(k,v)] -> k -> v | 365 | (!) :: (HasCallStack, Show k, Eq k) => [(k,v)] -> k -> v |
363 | (!) xs k = let Just x = lookup k xs in x | 366 | (!) xs k = case lookup k xs of |
367 | Just v -> v | ||
368 | Nothing -> error ("Missing field "++show k++" at "++prettyCallStack callStack) | ||
364 | 369 | ||
365 | -- Need this seperate for trailer calculation | 370 | -- Need this seperate for trailer calculation |
366 | signature_packet_start :: Packet -> B.ByteString | 371 | signature_packet_start :: Packet -> B.ByteString |
@@ -420,19 +425,28 @@ eccOID SecretKeyPacket { key = k } = lookup 'c' k >>= \(MPI oid) -> Just (snd $ | |||
420 | eccOID _ = Nothing | 425 | eccOID _ = Nothing |
421 | 426 | ||
422 | encode_public_key_material :: Packet -> [B.ByteString] | 427 | encode_public_key_material :: Packet -> [B.ByteString] |
423 | encode_public_key_material k | key_algorithm k `elem` [ECDSA,Ed25519] = do | 428 | encode_public_key_material k | key_algorithm k `elem` [ECDSA,Ed25519,ECC] = do |
424 | -- http://tools.ietf.org/html/rfc6637 | 429 | -- http://tools.ietf.org/html/rfc6637 |
425 | c <- maybeToList $ lookup 'c' (key k) | 430 | c <- maybeToList $ lookup 'c' (key k) |
426 | MPI l <- maybeToList $ lookup 'l' (key k) | 431 | MPI l <- maybeToList $ lookup 'l' (key k) |
427 | MPI x <- maybeToList $ lookup 'x' (key k) | ||
428 | MPI y <- maybeToList $ lookup 'y' (key k) | ||
429 | MPI flag <- maybeToList $ lookup 'f' (key k) | 432 | MPI flag <- maybeToList $ lookup 'f' (key k) |
430 | let (bitlen,oid) = B.splitAt 2 (encode c) | 433 | let (bitlen,oid) = B.splitAt 2 (encode c) |
431 | len16 = decode bitlen :: Word16 | 434 | len16 = decode bitlen :: Word16 |
432 | (fullbytes,rembits) = len16 `quotRem` 8 | 435 | (fullbytes,rembits) = len16 `quotRem` 8 |
433 | len8 = fromIntegral (fullbytes + if rembits/=0 then 1 else 0) :: Word8 | 436 | len8 = fromIntegral (fullbytes + if rembits/=0 then 1 else 0) :: Word8 |
434 | xy = flag*(4^l) + x*(2^l) + y -- flag could be 0x04 or 0x40 | 437 | eccstuff = case lookup 'e' (key k) of |
435 | [ len8 `B.cons` oid, encode (MPI xy) ] | 438 | Just stuff -> encode stuff |
439 | Nothing -> B.empty | ||
440 | case flag of | ||
441 | 0x40 -> do | ||
442 | MPI n <- maybeToList $ lookup 'n' (key k) | ||
443 | let xy = flag*(4^l) + n | ||
444 | [ len8 `B.cons` oid, encode (MPI xy), eccstuff ] | ||
445 | _ -> do | ||
446 | MPI x <- maybeToList $ lookup 'x' (key k) | ||
447 | MPI y <- maybeToList $ lookup 'y' (key k) | ||
448 | let xy = flag*(4^l) + x*(2^l) + y | ||
449 | [ len8 `B.cons` oid, encode (MPI xy), eccstuff ] | ||
436 | encode_public_key_material k = map (encode . (key k !)) (public_key_fields $ key_algorithm k) | 450 | encode_public_key_material k = map (encode . (key k !)) (public_key_fields $ key_algorithm k) |
437 | 451 | ||
438 | decode_public_key_material :: KeyAlgorithm -> Get [(Char,MPI)] | 452 | decode_public_key_material :: KeyAlgorithm -> Get [(Char,MPI)] |
@@ -442,30 +456,42 @@ decode_public_key_material algorithm | algorithm `elem` [ECDSA, Ed25519] = do | |||
442 | oidbytes <- getSomeByteString (fromIntegral oidlen) | 456 | oidbytes <- getSomeByteString (fromIntegral oidlen) |
443 | let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes) | 457 | let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes) |
444 | oid = mpiFromBytes oidbytes | 458 | oid = mpiFromBytes oidbytes |
445 | MPI xy <- get | 459 | MPI fxy <- get |
446 | let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2 | 460 | let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2 |
447 | width = ( integerBytesize xy - 1 ) `div` 2 | 461 | width = ( integerBytesize fxy - 1 ) `div` 2 |
448 | (fx,y) = xy `quotRem` (256^width) | ||
449 | (flag,x) = fx `quotRem` (256^width) | ||
450 | l = width*8 | 462 | l = width*8 |
451 | return [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y), ('f',MPI flag)] | 463 | (flag,xy) = fxy `quotRem` (256^(2*width)) |
464 | return $ case flag of | ||
465 | 0x40 -> [('c',oid), ('l',MPI l), ('n',MPI xy), ('f',MPI flag)] | ||
466 | _ -> let (x,y) = xy `quotRem` (256^width) | ||
467 | -- (fx,y) = xy `quotRem` (256^width) | ||
468 | -- (flag,x) = fx `quotRem` (256^width) | ||
469 | in [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y), ('f',MPI flag)] | ||
452 | decode_public_key_material ECC = do | 470 | decode_public_key_material ECC = do |
453 | -- http://tools.ietf.org/html/rfc6637 (9) Algorithm-Specific Fields for ECDH keys: | 471 | -- http://tools.ietf.org/html/rfc6637 (9) Algorithm-Specific Fields for ECDH keys: |
454 | oidlen <- get :: Get Word8 | 472 | oidlen <- get :: Get Word8 |
455 | oidbytes <- getSomeByteString (fromIntegral oidlen) | 473 | oidbytes <- getSomeByteString (fromIntegral oidlen) |
456 | let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes) | 474 | let mpiFromBytes bytes = MPI (getBigNum $ B.toStrict bytes) |
457 | oid = mpiFromBytes oidbytes | 475 | oid = mpiFromBytes oidbytes |
458 | MPI xy <- get | 476 | MPI fxy <- get |
459 | flen <- get :: Get Word8 | 477 | eccstuff <- get :: Get Word32 |
460 | one <- get :: Get Word8 | 478 | {- eccstuff is 4 one-byte fields: |
461 | hashid <- get :: Get Word8 | 479 | flen <- get :: Get Word8 |
462 | algoid <- get :: Get Word8 | 480 | one <- get :: Get Word8 -- always 0x01 |
481 | hashid <- get :: Get Word8 | ||
482 | algoid <- get :: Get Word8 | ||
483 | -} | ||
463 | let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2 | 484 | let integerBytesize i = fromIntegral $ LZ.length (encode (MPI i)) - 2 |
464 | width = ( integerBytesize xy - 1 ) `div` 2 | 485 | width = ( integerBytesize fxy - 1 ) `div` 2 |
465 | (fx,y) = xy `quotRem` (256^width) | ||
466 | (flag,x) = fx `quotRem` (256^width) | ||
467 | l = width*8 | 486 | l = width*8 |
468 | return [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y), ('f',MPI flag)] | 487 | (flag,xy) = fxy `quotRem` (256^(2*width)) |
488 | result = case flag of | ||
489 | 0x40 -> [('c',oid), ('l',MPI l), ('n',MPI xy), ('f',MPI flag)] | ||
490 | _ -> let (x,y) = xy `quotRem` (256^width) | ||
491 | -- (fx,y) = xy `quotRem` (256^width) | ||
492 | -- (flag,x) = fx `quotRem` (256^width) | ||
493 | in [('c',oid), ('l',MPI l), ('x',MPI x), ('y',MPI y), ('f',MPI flag)] | ||
494 | return $ result ++ [('e',MPI (fromIntegral eccstuff))] | ||
469 | decode_public_key_material algorithm = mapM (\f -> fmap ((,)f) get) (public_key_fields algorithm) | 495 | decode_public_key_material algorithm = mapM (\f -> fmap ((,)f) get) (public_key_fields algorithm) |
470 | 496 | ||
471 | put_packet :: Packet -> (B.ByteString, Word8) | 497 | put_packet :: Packet -> (B.ByteString, Word8) |
@@ -1130,6 +1156,7 @@ data SignatureSubpacket = | |||
1130 | hash :: B.ByteString | 1156 | hash :: B.ByteString |
1131 | } | | 1157 | } | |
1132 | EmbeddedSignaturePacket Packet | | 1158 | EmbeddedSignaturePacket Packet | |
1159 | -- TODO: IssuerFingerprintPacket (tag=33) | ||
1133 | UnsupportedSignatureSubpacket Word8 B.ByteString | 1160 | UnsupportedSignatureSubpacket Word8 B.ByteString |
1134 | deriving (Show, Read, Eq) | 1161 | deriving (Show, Read, Eq) |
1135 | 1162 | ||