PSP Security Protocol See https://github.com/google/psp/blob/main/doc/PSP_Arch_Spec.pdf
| 73 | |
| 74 | |
| 75 | class PSP(Packet): |
| 76 | """ |
| 77 | PSP Security Protocol |
| 78 | |
| 79 | See https://github.com/google/psp/blob/main/doc/PSP_Arch_Spec.pdf |
| 80 | """ |
| 81 | name = 'PSP' |
| 82 | |
| 83 | fields_desc = [ |
| 84 | ByteField('nexthdr', 0), |
| 85 | ByteField('hdrextlen', 1), |
| 86 | BitField("reserved", 0, 2), |
| 87 | BitField("cryptoffset", 0, 6), |
| 88 | BitField("sample", 0, 1), |
| 89 | BitField("drop", 0, 1), |
| 90 | BitField("version", 0, 4), |
| 91 | BitField("is_virt", 0, 1), |
| 92 | BitField("one_bit", 1, 1), |
| 93 | XIntField('spi', 0x00), |
| 94 | StrFixedLenField('iv', '\x00' * 8, 8), |
| 95 | ConditionalField(XIntField("virtkey", 0x00), lambda pkt: pkt.is_virt == 1), |
| 96 | ConditionalField(XIntField("sectoken", 0x00), lambda pkt: pkt.is_virt == 1), |
| 97 | XStrField('data', None), |
| 98 | ] |
| 99 | |
| 100 | def sanitize_cipher(self): |
| 101 | """ |
| 102 | Ensure we support the cipher to encrypt/decrypt this packet |
| 103 | |
| 104 | :returns: the supported cipher suite |
| 105 | :raise scapy.layers.psp.PSPCipherError: if the requested cipher |
| 106 | is unsupported |
| 107 | """ |
| 108 | if self.version not in (0, 1): |
| 109 | raise PSPCipherError('Can not encrypt/decrypt using unsupported version %s' |
| 110 | % (self.version)) |
| 111 | return aead.AESGCM |
| 112 | |
| 113 | def encrypt(self, key): |
| 114 | """ |
| 115 | Encrypt a PSP packet |
| 116 | |
| 117 | :param key: the secret key used for encryption |
| 118 | :raise scapy.layers.psp.PSPCipherError: if the requested cipher |
| 119 | is unsupported |
| 120 | """ |
| 121 | cipher = self.sanitize_cipher() |
| 122 | encrypt_start_offset = 16 + self.cryptoffset * 4 |
| 123 | iv = struct.pack("!L", self.spi) + self.iv |
| 124 | plain = b'' |
| 125 | to_encrypt = bytes(self.data) |
| 126 | self.data = b'' |
| 127 | psp_header = bytes(self) |
| 128 | header_length = len(psp_header) |
| 129 | # Header should always be fully plaintext |
| 130 | if header_length < encrypt_start_offset: |
| 131 | plain = to_encrypt[:encrypt_start_offset - header_length] |
| 132 | to_encrypt = to_encrypt[encrypt_start_offset - header_length:] |
nothing calls this directly
no test coverage detected