skrillax_packet/
lib.rs

1//! This crate mainly provides one trait: [Packet]. While you can implement it
2//! yourself, you might as well use the derive macro to derive it instead (which
3//! requires the `derive` feature).
4//! ```
5//! # #[cfg(feature = "derive")]
6//! # {
7//! # use skrillax_packet_derive::Packet;
8//! #[derive(Packet)]
9//! #[packet(opcode = 0x5001)]
10//! struct MyPacket {
11//!     content: String,
12//! }
13//! # }
14//! ```
15//!
16//! The rest of this crate focuses around converting a [Packet] into a
17//! [SilkroadFrame], or vice-versa. This currently takes a small detour through
18//! using either an [IncomingPacket] or [OutgoingPacket], depending on the
19//! direction. This is done because we often first need to apply some kind of
20//! transformation to the frames, before we can easily turn them into structs
21//! representing the packet. This would include combining multiple massive
22//! frames into one large buffer as well as decrypting the content of frames to
23//! figure out their opcodes. Thus, the chain goes something like this, in a
24//! simplified way. To turn a packet into frames:
25//! `myPacket.serialize().as_frames(context)` To turn frames into a packet:
26//! `IncomingPacket::from_frames(frames, context).try_into_packet::<MyPacket>()`
27//!
28//! However, this does require a bit more than just the [Packet] implementation.
29//! Either you need to implement the [TryFromPacket] and [AsPacket] traits
30//! yourself, or you need to implement/derive [skrillax_serde::Serialize](https://docs.rs/skrillax-serde/latest/skrillax_serde/trait.Serialize.html),
31//! [skrillax_serde::Deserialize](https://docs.rs/skrillax-serde/latest/skrillax_serde/trait.Deserialize.html),
32//! and [skrillax_serde::ByteSize](https://docs.rs/skrillax-serde/latest/skrillax_serde/trait.ByteSize.html)
33//! from the [skrillax_serde](https://docs.rs/skrillax-serde/latest/skrillax_serde/) crate.
34//! With these, [AsPacket] and [TryFromPacket] are automatically
35//! implemented for you. They are necessary to serialize/deserialize the packet
36//! content into bytes, which can be sent using the frames.
37//!
38//! ## Derive
39//!
40//! The derive macro currently has three options, for all the options the trait
41//! provides:
42//! ```
43//! # #[cfg(feature = "derive")]
44//! # {
45//! # use skrillax_packet_derive::Packet;
46//! #[derive(Packet)]
47//! #[packet(opcode = 0x5001, encrypted = true, massive = false)]
48//! struct MyPacket {
49//!     content: String,
50//! }
51//! # }
52//! ```
53//! `encrypted` and `massive` are `false` by default and are mutually exclusive.
54//! `opcode` is a required attribute, this is also considered the `ID` of a
55//! packet. The name is automatically considered to be the structure's name.
56
57use bytes::{BufMut, Bytes, BytesMut};
58use skrillax_codec::SilkroadFrame;
59use skrillax_security::handshake::CheckBytesInitialization;
60use skrillax_security::{Checksum, ChecksumBuilder, MessageCounter, SilkroadEncryption};
61use std::sync::Mutex;
62use thiserror::Error;
63
64#[cfg(feature = "derive")]
65pub use skrillax_packet_derive::Packet;
66#[cfg(feature = "serde")]
67use skrillax_serde::{ByteSize, Deserialize, SerializationError, Serialize};
68
69#[derive(Error, Debug)]
70pub enum PacketError {
71    #[cfg(feature = "serde")]
72    #[error("An error occurred while trying to (de)serialize the packet")]
73    SerializationError(#[from] SerializationError),
74    #[error(
75        "An encrypted packet was either attempted to be sent or received, but no security has \
76         been established yet"
77    )]
78    MissingSecurity,
79}
80
81/// Defines associated constants with this packet, which can be used to turn
82/// this struct into a packet.
83///
84/// If this struct also implements [skrillax_serde::ByteSize](https://docs.rs/skrillax-serde/latest/skrillax_serde/trait.ByteSize.html)
85/// and [skrillax_serde::Serialize](https://docs.rs/skrillax-serde/latest/skrillax_serde/trait.Serialize.html),
86/// it will automatically gain [AsPacket]. If it implements
87/// [skrillax_serde::Deserialize](https://docs.rs/skrillax-serde/latest/skrillax_serde/trait.Deserialize.html), it will automatically gain [TryFromPacket].
88/// This can automatically be derived with the `derive` feature.
89pub trait Packet {
90    /// Defines the ID or OpCode of the packet.
91    const ID: u16;
92    /// Provides a more readable name for the given packet. This is usually just
93    /// the struct name.
94    const NAME: &'static str;
95    /// Defines if this packet is a massive packet, and should thus use massive
96    /// frames for transport.
97    const MASSIVE: bool;
98    /// Defines if this packet is an encrypted packet.
99    const ENCRYPTED: bool;
100}
101
102/// An incoming packet that has already gone through re-framing of massive
103/// packets or decryption. It is essentially a collection of bytes for a given
104/// opcode, nothing more.
105#[derive(Eq, PartialEq, Debug)]
106pub struct IncomingPacket {
107    opcode: u16,
108    data: Bytes,
109}
110
111impl IncomingPacket {
112    /// Creates a new packet given the opcode and contained data.
113    pub fn new(opcode: u16, data: Bytes) -> Self {
114        Self { opcode, data }
115    }
116
117    /// Consumes this packet, return the contained data.
118    pub fn consume(self) -> (u16, Bytes) {
119        (self.opcode, self.data)
120    }
121
122    pub fn opcode(&self) -> u16 {
123        self.opcode
124    }
125
126    pub fn data(&self) -> &[u8] {
127        &self.data
128    }
129}
130
131/// A packet on its way out, before having been turned into a frame.
132///
133/// In turn, we still need to know what kind of frame it should end up as.
134/// Generally, one outgoing packet will result in a single frame, but
135/// multiple packets can be combined to a massive packet. This will
136/// span multiple frames, including an additional header.
137#[derive(Eq, PartialEq, Debug)]
138pub enum OutgoingPacket {
139    /// A packet that shall be encrypted before being sent out.
140    Encrypted { opcode: u16, data: Bytes },
141    /// A basic packet that doesn't need any additional transformation.
142    Simple { opcode: u16, data: Bytes },
143    /// A massive packet containing multiple inner packets that should be sent
144    /// together.
145    Massive { opcode: u16, packets: Vec<Bytes> },
146}
147
148/// Defines _something_ that can be turned into a packet, which then can be sent
149/// out.
150///
151/// Generally, this will be either a single struct representing a single
152/// operation, or a 'protocol' enum containing a list of multiple packets. For
153/// convenience, this trait has a blanket implementation for everything which
154/// already implements [Packet] and [Deserialize](https://docs.rs/skrillax-serde/latest/skrillax_serde/trait.Deserialize.html).
155///
156/// The analog is [TryFromPacket].
157pub trait AsPacket {
158    /// Serializes this structure into a packet that can be sent over the wire.
159    fn as_packet(&self) -> OutgoingPacket;
160}
161
162impl<T: AsPacket> From<T> for OutgoingPacket {
163    fn from(value: T) -> Self {
164        value.as_packet()
165    }
166}
167
168/// Defines _something_ that can be created from a packet, after it has been
169/// received.
170///
171/// Once a re-framing, decryption and other parts have completed, we want to
172/// turn the contained data into a usable structure.
173///
174/// The analog is [AsPacket].
175pub trait TryFromPacket {
176    /// Tries to create `Self` from the given data. Unlike [AsPacket], we
177    /// do not deal with the opcode here. It is expected that we have
178    /// already matched the opcode to `Self` and know it matches.
179    ///
180    /// `data` _may_ contain more data than necessary to form a single packet,
181    /// for example if we were inside a massive frame. Thus, we need to
182    /// return the amount of consumed bytes such that the remainder may be
183    /// used to create more elements of `Self` if the caller wants to.
184    fn try_deserialize(data: &[u8]) -> Result<(usize, Self), PacketError>
185    where
186        Self: Sized;
187}
188
189#[cfg(feature = "serde")]
190impl<T> TryFromPacket for T
191where
192    T: Packet + Deserialize + Send + Sized,
193{
194    fn try_deserialize(data: &[u8]) -> Result<(usize, Self), PacketError> {
195        use bytes::Buf;
196        let mut reader = data.reader();
197        let read = Self::read_from(&mut reader)?;
198        let consumed = data.len() - reader.into_inner().len();
199        Ok((consumed, read))
200    }
201}
202
203#[cfg(feature = "serde")]
204impl<T> AsPacket for [T]
205where
206    T: Packet + Serialize + ByteSize,
207{
208    fn as_packet(&self) -> OutgoingPacket {
209        use std::cmp::{max, min};
210        assert!(T::MASSIVE, "Can only transform massive packets");
211        let total_size = self.iter().map(|p| p.byte_size()).sum();
212        let mut buffer = BytesMut::with_capacity(total_size);
213        for p in self {
214            p.write_to(&mut buffer);
215        }
216
217        let mut data = buffer.freeze();
218        let required_packets = max(data.len() / 0x7FFF, 1);
219
220        let mut result = Vec::with_capacity(required_packets);
221        for _ in 0..required_packets {
222            result.push(data.split_to(min(0x7FFF, data.len())));
223        }
224
225        OutgoingPacket::Massive {
226            opcode: T::ID,
227            packets: result,
228        }
229    }
230}
231
232#[cfg(feature = "serde")]
233impl<T> AsPacket for T
234where
235    T: Packet + Serialize + ByteSize,
236{
237    fn as_packet(&self) -> OutgoingPacket {
238        use std::cmp::{max, min};
239
240        let mut buffer = BytesMut::with_capacity(self.byte_size());
241        self.write_to(&mut buffer);
242        if Self::MASSIVE {
243            let mut data = buffer.freeze();
244            let required_packets = max(data.len() / 0x7FFF, 1);
245
246            let mut result = Vec::with_capacity(required_packets);
247            for _ in 0..required_packets {
248                result.push(data.split_to(min(0x7FFF, data.len())));
249            }
250
251            OutgoingPacket::Massive {
252                opcode: Self::ID,
253                packets: result,
254            }
255        } else if Self::ENCRYPTED {
256            OutgoingPacket::Encrypted {
257                opcode: Self::ID,
258                data: buffer.freeze(),
259            }
260        } else {
261            OutgoingPacket::Simple {
262                opcode: Self::ID,
263                data: buffer.freeze(),
264            }
265        }
266    }
267}
268
269#[derive(Error, Debug)]
270pub enum FramingError {
271    #[error("Tried to create an encrypted frame but no encrypted was set up")]
272    MissingEncryption,
273}
274
275/// A procedure to turn an element into actual [SilkroadFrame]s,
276/// which can be written by the codec onto the wire.
277pub trait AsFrames {
278    /// Creates a collection of [SilkroadFrame] that represent
279    /// the given structure.
280    ///
281    /// This is mostly a 1-to-1 mapping between output packet
282    /// kinds and their respective frames. Since frames may be encrypted,
283    /// this can optionally receive the security to be used. If no
284    /// security is passed, but an encrypted packet is requested, this
285    /// may error.
286    fn as_frames(&self, context: SecurityContext) -> Result<Vec<SilkroadFrame>, FramingError>;
287}
288
289impl AsFrames for OutgoingPacket {
290    fn as_frames(&self, context: SecurityContext) -> Result<Vec<SilkroadFrame>, FramingError> {
291        let count = context
292            .checkers()
293            .map(|check| check.generate_count_byte())
294            .unwrap_or(0);
295
296        match self {
297            OutgoingPacket::Encrypted { opcode, data } => {
298                let Some(encryption) = context.encryption() else {
299                    return Err(FramingError::MissingEncryption);
300                };
301                let content_length = data.len() + 4;
302                let length_with_padding = SilkroadEncryption::find_encrypted_length(content_length);
303                let mut new_buffer = BytesMut::with_capacity(length_with_padding);
304                new_buffer.put_u16_le(*opcode);
305                new_buffer.put_u8(count);
306                new_buffer.put_u8(0);
307                new_buffer.put_slice(data);
308
309                if let Some(mut checksum_builder) = context
310                    .checkers()
311                    .map(|checkers| checkers.checksum_builder())
312                {
313                    checksum_builder.update(&(data.len() as u16 | 0x8000).to_le_bytes());
314                    checksum_builder.update(&new_buffer);
315                    new_buffer[3] = checksum_builder.digest();
316                }
317
318                for _ in 0..(length_with_padding - content_length) {
319                    new_buffer.put_u8(0);
320                }
321
322                encryption
323                    .encrypt_mut(&mut new_buffer)
324                    .expect("Should be able to encrypt");
325                Ok(vec![SilkroadFrame::Encrypted {
326                    content_size: data.len(),
327                    encrypted_data: new_buffer.freeze(),
328                }])
329            },
330            OutgoingPacket::Simple { opcode, data } => {
331                let crc = if let Some(mut checksum_builder) = context
332                    .checkers()
333                    .map(|checkers| checkers.checksum_builder())
334                {
335                    checksum_builder.update(&(data.len() as u16).to_le_bytes());
336                    checksum_builder.update(&opcode.to_le_bytes());
337                    checksum_builder.update_byte(count);
338                    checksum_builder.update_byte(0);
339                    checksum_builder.update(data);
340                    checksum_builder.digest()
341                } else {
342                    0
343                };
344
345                Ok(vec![SilkroadFrame::Packet {
346                    count,
347                    crc,
348                    opcode: *opcode,
349                    data: data.clone(),
350                }])
351            },
352            OutgoingPacket::Massive { opcode, packets } => {
353                let mut frames = Vec::with_capacity(1 + packets.len());
354
355                let crc = if let Some(mut checksum_builder) = context
356                    .checkers()
357                    .map(|checkers| checkers.checksum_builder())
358                {
359                    checksum_builder.update(&5u16.to_le_bytes());
360                    checksum_builder.update(&0x600Du16.to_le_bytes());
361                    checksum_builder.update_byte(count);
362                    checksum_builder.update_byte(0);
363                    checksum_builder.update_byte(1);
364                    checksum_builder.update(&opcode.to_le_bytes());
365                    checksum_builder.update(&(packets.len() as u16).to_le_bytes());
366                    checksum_builder.digest()
367                } else {
368                    0
369                };
370
371                frames.push(SilkroadFrame::MassiveHeader {
372                    count,
373                    crc,
374                    contained_opcode: *opcode,
375                    contained_count: packets.len() as u16,
376                });
377
378                for packet in packets.iter() {
379                    let count = context
380                        .checkers()
381                        .map(|check| check.generate_count_byte())
382                        .unwrap_or(0);
383
384                    let crc = if let Some(mut checksum_builder) = context
385                        .checkers()
386                        .map(|checkers| checkers.checksum_builder())
387                    {
388                        checksum_builder.update(&((packet.len() + 1) as u16).to_le_bytes());
389                        checksum_builder.update(&0x600Du16.to_le_bytes());
390                        checksum_builder.update_byte(count);
391                        checksum_builder.update_byte(0);
392                        checksum_builder.update_byte(0);
393                        checksum_builder.update(packet);
394                        checksum_builder.digest()
395                    } else {
396                        0
397                    };
398
399                    frames.push(SilkroadFrame::MassiveContainer {
400                        count,
401                        crc,
402                        inner: packet.clone(),
403                    });
404                }
405
406                Ok(frames)
407            },
408        }
409    }
410}
411
412#[derive(Error, Debug)]
413pub enum ReframingError {
414    #[error("We don't have enough packets to complete the re-framing")]
415    Incomplete(Option<usize>),
416    #[error("Cannot handle a massive container without a header")]
417    StrayMassiveContainer,
418    #[error("Found a mixture of massive and non-massive frames")]
419    MixedFrames,
420    #[error("Encountered an encrypted packet but was not provided a security setup")]
421    MissingSecurity,
422    #[error("The decryption of an encrypted packet did not yield a simple frame")]
423    InvalidEncryptedData,
424    #[error("The CRC byte was {received} by we expected to to be {expected}")]
425    CrcCheckFailed { expected: u8, received: u8 },
426    #[error("The count byte was {received} by we expected to to be {expected}")]
427    CounterCheckFailed { expected: u8, received: u8 },
428}
429
430/// Provides a way to turn [SilkroadFrame]s into an [IncomingPacket].
431pub trait FromFrames {
432    type Output;
433    /// Try to turn _all_ frames into an incoming packet.
434    ///
435    /// This accepts a slice of frames, which is either a single packet frame
436    /// (plain or encrypted), or multiple frames representing a massive
437    /// packet. As such, this function does not return how many frames may
438    /// have been consumed, as it is expected to have consumed all the given
439    /// frames.
440    ///
441    /// It requires a security context such that it may validate and decrypt
442    /// frames, when the need arises. If no security is provided but an
443    /// encrypted frame is encountered, it will error.
444    fn from_frames(
445        frames: &[SilkroadFrame],
446        security: SecurityContext,
447    ) -> Result<Self::Output, ReframingError>;
448}
449
450struct MassiveInfo {
451    opcode: u16,
452    remaining: u16,
453}
454
455impl FromFrames for IncomingPacket {
456    type Output = IncomingPacket;
457
458    fn from_frames(
459        frames: &[SilkroadFrame],
460        security: SecurityContext,
461    ) -> Result<Self, ReframingError> {
462        let mut massive_information: Option<MassiveInfo> = None;
463        let mut massive_buffer: Option<BytesMut> = None;
464        for (i, frame) in frames.iter().enumerate() {
465            match frame {
466                SilkroadFrame::Packet { .. } | SilkroadFrame::Encrypted { .. }
467                    if massive_information.is_some() =>
468                {
469                    return Err(ReframingError::MixedFrames);
470                },
471                SilkroadFrame::Packet {
472                    opcode,
473                    data,
474                    count,
475                    crc,
476                } => {
477                    if let Some(checkers) = security.checkers() {
478                        let expected_count = checkers.generate_count_byte();
479                        if *count != expected_count {
480                            return Err(ReframingError::CounterCheckFailed {
481                                expected: expected_count,
482                                received: *count,
483                            });
484                        }
485
486                        let mut checksum_builder = checkers.checksum_builder();
487                        checksum_builder.update(&(data.len() as u16).to_le_bytes());
488                        checksum_builder.update(&opcode.to_le_bytes());
489                        checksum_builder.update_byte(*count);
490                        checksum_builder.update_byte(0);
491                        checksum_builder.update(data);
492                        let expected_crc = checksum_builder.digest();
493                        if *crc != expected_crc {
494                            return Err(ReframingError::CrcCheckFailed {
495                                expected: expected_crc,
496                                received: *crc,
497                            });
498                        }
499                    }
500
501                    return Ok(IncomingPacket::new(*opcode, data.clone()));
502                },
503                SilkroadFrame::Encrypted {
504                    encrypted_data,
505                    content_size,
506                } => {
507                    let Some(encryption) = security.encryption() else {
508                        return Err(ReframingError::MissingSecurity);
509                    };
510
511                    let decrypted = encryption
512                        .decrypt(encrypted_data)
513                        .expect("Should be able to decrypt bytes");
514
515                    let frame = SilkroadFrame::from_data(&decrypted[0..(*content_size + 4)]);
516                    return match frame {
517                        SilkroadFrame::Packet {
518                            opcode,
519                            data,
520                            count,
521                            crc,
522                        } => {
523                            if let Some(checkers) = security.checkers() {
524                                let expected_count = checkers.generate_count_byte();
525                                if count != expected_count {
526                                    return Err(ReframingError::CounterCheckFailed {
527                                        expected: expected_count,
528                                        received: count,
529                                    });
530                                }
531
532                                let mut checksum_builder = checkers.checksum_builder();
533                                checksum_builder
534                                    .update(&(data.len() as u16 | 0x8000).to_le_bytes());
535                                checksum_builder.update(&opcode.to_le_bytes());
536                                checksum_builder.update_byte(count);
537                                checksum_builder.update_byte(0);
538                                checksum_builder.update(&data);
539                                let expected_crc = checksum_builder.digest();
540                                if crc != expected_crc {
541                                    return Err(ReframingError::CrcCheckFailed {
542                                        expected: expected_crc,
543                                        received: crc,
544                                    });
545                                }
546                            }
547                            Ok(IncomingPacket::new(opcode, data))
548                        },
549                        _ => Err(ReframingError::InvalidEncryptedData),
550                    };
551                },
552                SilkroadFrame::MassiveHeader {
553                    contained_count,
554                    contained_opcode,
555                    count,
556                    crc,
557                } => {
558                    let required_frames = *contained_count as usize;
559                    let remaining_frames = frames.len() - (i + 1);
560                    if required_frames > remaining_frames {
561                        return Err(ReframingError::Incomplete(Some(required_frames)));
562                    }
563
564                    if let Some(checkers) = security.checkers() {
565                        let expected_count = checkers.generate_count_byte();
566                        if *count != expected_count {
567                            return Err(ReframingError::CounterCheckFailed {
568                                expected: expected_count,
569                                received: *count,
570                            });
571                        }
572
573                        let mut checksum_builder = checkers.checksum_builder();
574                        checksum_builder.update(&5u16.to_le_bytes());
575                        checksum_builder.update(&0x600Du16.to_le_bytes());
576                        checksum_builder.update_byte(*count);
577                        checksum_builder.update_byte(0);
578                        checksum_builder.update_byte(1);
579                        checksum_builder.update(&contained_opcode.to_le_bytes());
580                        checksum_builder.update(&contained_count.to_le_bytes());
581                        let expected_crc = checksum_builder.digest();
582                        if *crc != expected_crc {
583                            return Err(ReframingError::CrcCheckFailed {
584                                expected: expected_crc,
585                                received: *crc,
586                            });
587                        }
588                    }
589
590                    massive_information = Some(MassiveInfo {
591                        opcode: *contained_opcode,
592                        remaining: *contained_count,
593                    });
594                },
595                SilkroadFrame::MassiveContainer { inner, count, crc } => {
596                    if let Some(mut massive) = massive_information.take() {
597                        let mut current_buffer = massive_buffer.take().unwrap_or_default();
598                        current_buffer.extend_from_slice(inner);
599
600                        massive.remaining = massive.remaining.saturating_sub(1);
601
602                        if let Some(checkers) = security.checkers() {
603                            let expected_count = checkers.generate_count_byte();
604                            if *count != expected_count {
605                                return Err(ReframingError::CounterCheckFailed {
606                                    expected: expected_count,
607                                    received: *count,
608                                });
609                            }
610
611                            let mut checksum_builder = checkers.checksum_builder();
612                            checksum_builder.update(&(1u16 + inner.len() as u16).to_le_bytes());
613                            checksum_builder.update(&0x600Du16.to_le_bytes());
614                            checksum_builder.update_byte(*count);
615                            checksum_builder.update_byte(0);
616                            checksum_builder.update_byte(1);
617                            checksum_builder.update(inner);
618                            let expected_crc = checksum_builder.digest();
619                            if *crc != expected_crc {
620                                return Err(ReframingError::CrcCheckFailed {
621                                    expected: expected_crc,
622                                    received: *crc,
623                                });
624                            }
625                        }
626
627                        if massive.remaining == 0 {
628                            return Ok(IncomingPacket::new(
629                                massive.opcode,
630                                current_buffer.freeze(),
631                            ));
632                        } else {
633                            massive_buffer = Some(current_buffer);
634                            massive_information = Some(massive);
635                        }
636                    } else {
637                        return Err(ReframingError::StrayMassiveContainer);
638                    }
639                },
640            }
641        }
642
643        Err(ReframingError::Incomplete(
644            massive_information.map(|massive| massive.remaining as usize),
645        ))
646    }
647}
648
649/// Container for [MessageCounter] and [Checksum].
650pub struct SecurityBytes {
651    counter: Mutex<MessageCounter>,
652    checksum: Checksum,
653}
654
655impl SecurityBytes {
656    pub fn from_seeds(crc_seed: u32, count_seed: u32) -> Self {
657        Self {
658            counter: Mutex::new(MessageCounter::new(count_seed)),
659            checksum: Checksum::new(crc_seed),
660        }
661    }
662
663    /// Generate the next count byte.
664    ///
665    /// A count byte is used to avoid replay attacks, used to determine a
666    /// continuous flow of the data. If a packet is dropped, or another
667    /// injected, this will no longer match. It is essentially a seeded RNG
668    /// number.
669    pub fn generate_count_byte(&self) -> u8 {
670        self.counter
671            .lock()
672            .expect("Should be able to lock the counter for increasing it")
673            .next_byte()
674    }
675
676    pub fn generate_checksum(&self, data: &[u8]) -> u8 {
677        self.checksum.generate_byte(data)
678    }
679
680    pub fn checksum_builder(&self) -> ChecksumBuilder {
681        self.checksum.builder()
682    }
683}
684
685// Technically, this is not the right place. But due to the orphan rule, it's
686// the most suitable place.
687impl From<CheckBytesInitialization> for SecurityBytes {
688    fn from(value: CheckBytesInitialization) -> Self {
689        SecurityBytes::from_seeds(value.crc_seed, value.count_seed)
690    }
691}
692
693/// Provides a complete security context to handle packets.
694///
695/// To properly handle all security features of a Silkroad Online packet, you
696/// may need all three elements: [SilkroadEncryption], [MessageCounter], and
697/// [Checksum]. However, it is possible for either the [SilkroadEncryption] to
698/// be absent and/or both [MessageCounter] and [Checksum] to be absent. Thus,
699/// [MessageCounter] and [Checksum] are tied together. This struct does not
700/// really provide much in and of itself, but it is handy as it might be used in
701/// different layers in the stack to refer to.
702#[derive(Default)]
703pub struct SecurityContext<'a> {
704    encryption: Option<&'a SilkroadEncryption>,
705    checkers: Option<&'a SecurityBytes>,
706}
707
708impl<'a> SecurityContext<'a> {
709    pub fn new(
710        encryption: Option<&'a SilkroadEncryption>,
711        security_bytes: Option<&'a SecurityBytes>,
712    ) -> Self {
713        Self {
714            encryption,
715            checkers: security_bytes,
716        }
717    }
718
719    /// Provide the established encryption, if present.
720    pub fn encryption(&self) -> Option<&SilkroadEncryption> {
721        self.encryption
722    }
723
724    /// Provide the security bytes/checkers, if present.
725    pub fn checkers(&self) -> Option<&SecurityBytes> {
726        self.checkers
727    }
728}