Tag11Packet   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 103
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 103
ccs 41
cts 41
cp 1
rs 10
c 0
b 0
f 0
wmc 11

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A generate() 0 10 1
C parse() 0 49 9
1
<?php
2
3
/*
4
 * This file is part of the PHP EcryptFS library.
5
 * (c) 2017 by Dennis Birkholz
6
 * All rights reserved.
7
 * For the license to use this library, see the provided LICENSE file.
8
 */
9
10
namespace Iqb\Ecryptfs;
11
12
/**
13
 * Literal Data Packet (Tag 11)
14
 *
15
 * @author Dennis Birkholz <[email protected]>
16
 * @link https://tools.ietf.org/html/rfc2440#section-5.9 OpenPGP Message Format: Literal Data Packet (Tag 11)
17
 * @link https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/ecryptfs/keystore.c?h=v4.11.3#n1536 parse_tag_11_packet
18
 * @link https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/ecryptfs/keystore.c?h=v4.11.3#n2123 write_tag_11_packet
19
 */
20
final class Tag11Packet
21
{
22
    /**
23
     * @link https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/ecryptfs/ecryptfs_kernel.h?h=v4.11.3#n141
24
     */
25
    const PACKET_TYPE = 0xED;
26
27
    const MIN_PACKET_LENGTH = 14;
28
29
    /**
30
     * Binary data format specifier, see keystore.c
31
     * @link https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/ecryptfs/keystore.c?h=v4.11.3#n1611
32
     */
33
    const FORMAT_SPECIFIER = 0x62;
34
35
    /**
36
     * Hardcoded filename field
37
     * @link https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/ecryptfs/keystore.c?h=v4.11.3#n2148
38
     */
39
    const PACKET_FILENAME = '_CONSOLE';
40
41
    /**
42
     * @var string
43
     */
44
    public $contents;
45
46
47 2
    public function __construct($contents)
48
    {
49 2
        $this->contents = $contents;
50 2
    }
51
52
53
    /**
54
     * Generate the binary representation of this packet
55
     */
56 1
    public function generate() : string
57
    {
58
        return
59 1
            \chr(self::PACKET_TYPE)
60 1
            . \chr(self::MIN_PACKET_LENGTH + \strlen($this->contents)) // FIXME: handle packet size > 191
61 1
            . \chr(self::FORMAT_SPECIFIER)
62 1
            . \chr(\strlen(self::PACKET_FILENAME))
63 1
            . self::PACKET_FILENAME
64 1
            . \chr(0).\chr(0).\chr(0).\chr(0)
65 1
            . $this->contents
66
        ;
67
    }
68
69
70
    /**
71
     * Try to parse a Tag11 packet from the supplied data string.
72
     * If the parsing was successfully, $pos will be incremented to point after the parsed data.
73
     */
74 10
    public static function parse(string $data, int &$pos = 0) : self
75
    {
76 10
        $cur = $pos;
77 10
        $remaining = \strlen($data) - $cur;
78
79 10
        if ($remaining < self::MIN_PACKET_LENGTH+2) {
80 1
            throw new ParseException('Not enough data available to read for minimum packet length.');
81
        }
82
83 9
        if (\ord($data[$cur]) !== self::PACKET_TYPE) {
84 1
            throw new ParseException("Expected packet type marker 0x" . \bin2hex(self::PACKET_TYPE) . " but found 0x" . \bin2hex(\ord($data[$cur])));
85
        }
86 8
        $cur++;
87
88 8
        $packetSize = Util::parseTagPacketLength($data, $cur);
89 7
        if ($packetSize < self::MIN_PACKET_LENGTH) {
90 1
            throw new ParseException("Invalid packet size, minimum packet size is " . self::MIN_PACKET_LENGTH . " but got " . $packetSize);
91
        }
92
93 6
        $remaining -= ($cur - $pos);
94 6
        if ($remaining < $packetSize) {
95 1
            throw new ParseException("Corrupt packet.");
96
        }
97
98 5
        if (\ord($data[$cur++]) !== self::FORMAT_SPECIFIER) {
99 1
            throw new ParseException('Invalid format specifier');
100
        }
101
102 4
        $filenameLength = \ord($data[$cur++]);
103 4
        if ($filenameLength !== \strlen(self::PACKET_FILENAME)) {
104 1
            throw new ParseException("Expected filename length of " . \strlen(self::PACKET_FILENAME) . " but got " . $filenameLength);
105
        }
106
107 3
        $filename = \substr($data, $cur, $filenameLength);
108 3
        if ($filename !== self::PACKET_FILENAME) {
109 1
            throw new ParseException('Invalid filename "' . $filename . '", expected "' . self::PACKET_FILENAME . '".');
110
        }
111 2
        $cur += $filenameLength;
112
113 2
        if (\substr($data, $cur, 4) !== \chr(0).\chr(0).\chr(0).\chr(0)) {
114 1
            throw new ParseException('Expected file date to be zero.');
115
        }
116 1
        $cur += 4;
117
118 1
        $tag = new self(\substr($data, $cur, ($packetSize - self::MIN_PACKET_LENGTH)));
119 1
        $cur += ($packetSize - self::MIN_PACKET_LENGTH);
120
121 1
        $pos = $cur;
122 1
        return $tag;
123
    }
124
}
125