summary refs log tree commit diff
path: root/crypto/src/openpgp/SXprUtilities.cs
blob: 835d3c3474e4b30f0d1c615176130005ed8fadc5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
using System;
using System.IO;

using Org.BouncyCastle.Utilities.IO;

namespace Org.BouncyCastle.Bcpg.OpenPgp
{
    /**
     * Utility functions for looking a S-expression keys. This class will move when it finds a better home!
     * <p>
     * Format documented here:
     * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master
     * </p>
     */
    public sealed class SXprUtilities
    {
        private SXprUtilities()
        {
        }

        private static int ReadLength(Stream input, int ch)
        {
            int len = ch - '0';

            while ((ch = input.ReadByte()) >= 0 && ch != ':')
            {
                len = len * 10 + ch - '0';
            }

            return len;
        }

        internal static string ReadString(Stream input, int ch)
        {
            int len = ReadLength(input, ch);

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
            return string.Create(len, input, (chars, input) =>
            {
                for (int i = 0; i < chars.Length; ++i)
                {
                    chars[i] = Convert.ToChar(input.ReadByte());
                }
            });
#else
            char[] chars = new char[len];

            for (int i = 0; i != chars.Length; i++)
            {
                chars[i] = (char)input.ReadByte();
            }

            return new string(chars);
#endif
        }

        internal static byte[] ReadBytes(Stream input, int ch)
        {
            int len = ReadLength(input, ch);

            byte[] data = new byte[len];

            Streams.ReadFully(input, data);

            return data;
        }

        internal static S2k ParseS2k(Stream input)
        {
            SkipOpenParenthesis(input);

            string alg = ReadString(input, input.ReadByte());
            byte[] iv = ReadBytes(input, input.ReadByte());
            long iterationCount = long.Parse(ReadString(input, input.ReadByte()));

            SkipCloseParenthesis(input);

            // we have to return the actual iteration count provided.
            return new MyS2k(HashAlgorithmTag.Sha1, iv, iterationCount);
        }

        internal static void SkipOpenParenthesis(Stream input)
        {
            int ch = input.ReadByte();
            if (ch != '(')
                throw new IOException("unknown character encountered");
        }

        internal static void SkipCloseParenthesis(Stream input)
        {
            int ch = input.ReadByte();
            if (ch != ')')
                throw new IOException("unknown character encountered");
        }

        private class MyS2k : S2k
        {
            private readonly long mIterationCount64;

            internal MyS2k(HashAlgorithmTag algorithm, byte[] iv, long iterationCount64)
                : base(algorithm, iv, (int)iterationCount64)
            {
                this.mIterationCount64 = iterationCount64;
            }

            public override long IterationCount
            {
                get { return mIterationCount64; }
            }
        }
    }
}