String of hexadecimal numbers don't align properly in tabular cell

Not too difficult if your editor supports replace all in selection.

\documentclass{article}

\def\xor{\oplus}

\begin{document}

\noindent\begin{tabular}{ |c| r*{15}{@{ }r}| }
    \hline
        $C_2$ & B5 & 6E & 2C &  D4 & F3 & 12 & 57 & 3E & 8C & 8C & 1A & 77 & A3 & EE & C3 & 41 \\ 
        $P'_3 \xor P_3$ & 00 & 00 & 00 & 00 & 00 & 0F & 00 & 03 & 00 & 00 & 00 & 00 & 00 & 00 & 00 & 00 \\
        $C'_2$ & B5 & 6E & 2C & D4 & F3 & 1D & 57 & 3D & 8C & 8C & 1A & 77 & A3 & EE & C3 & 41\\
    \hline
\end{tabular}

\end{document}

demo


Just for fun, how to avoid changing the input with so many &:

\documentclass{article}
%\usepackage{xparse} % not necessary with LaTeX 2020-10-01
\usepackage{array,booktabs}

\newcommand{\xor}{\oplus}

\ExplSyntaxOn
\NewDocumentCommand{\bytetable}{O{\textwidth}m}
 {
  \dutt_bytetable:nn { #1 } { #2 }
 }

\int_new:N \l__dutt_bytetable_bytes_int
\seq_new:N \l__dutt_bytetable_rows_seq
\seq_new:N \l__dutt_bytetable_row_seq
\seq_new:N \l__dutt_bytetable_bytes_seq
\tl_new:N \l__dutt_bytetable_temp_tl
\tl_new:N \l__dutt_bytetable_body_tl

\cs_generate_variant:Nn \seq_set_split:Nnn { Nne }

\cs_new_protected:Nn \dutt_bytetable:nn
 {
  \seq_set_split:Nnn \l__dutt_bytetable_rows_seq { \\ } { #2 }
  % examine the part after the last \\
  \seq_pop_right:NN \l__dutt_bytetable_rows_seq \l__dutt_bytetable_temp_tl
  \tl_if_empty:NF \l__dutt_bytetable_temp_tl
   {% not empty, reinsert
    \seq_put_right:NV \l__dutt_bytetable_rows_seq \l__dutt_bytetable_temp_tl
   }
  % let's build the body of the table
  \tl_clear:N \l__dutt_bytetable_body_tl
  \int_zero:N \l__dutt_bytetable_bytes_int % this counts the number of bytes
  % examine each row
  \seq_map_inline:Nn \l__dutt_bytetable_rows_seq
   {
    % separate the parts before and after &
    \seq_set_split:Nnn \l__dutt_bytetable_row_seq { & } { ##1 }
    % in the second part we need to split at spaces
    \seq_set_split:Nne \l__dutt_bytetable_bytes_seq { ~ }
     {
      \seq_item:Nn \l__dutt_bytetable_row_seq { 2 }
     }
    % count the number of parts in the bytes section
    \int_set:Nn \l__dutt_bytetable_bytes_int
     {
      \int_max:nn { \l__dutt_bytetable_bytes_int } { \seq_count:N \l__dutt_bytetable_bytes_seq }
     }
    % add the row to the table
    \tl_put_right:Nx \l__dutt_bytetable_body_tl
     {
      % first the part before &
      \seq_item:Nn \l__dutt_bytetable_row_seq { 1 } &
      % then the rest, with & in between each item
      \seq_use:Nn \l__dutt_bytetable_bytes_seq { & }
      % the endline marker
      \exp_not:N \\
     }
   }
  % output the table
  \group_begin:
  \setlength{\tabcolsep}{0pt}
  \begin{tabular*}{#1}
   {
    @{\extracolsep{\fill}}
    >{$}c<{$}
    *{\l__dutt_bytetable_bytes_int}{c}
   }
  \toprule
  \l__dutt_bytetable_body_tl
  \bottomrule
  \end{tabular*}
  \group_end:
 }

\ExplSyntaxOff

\begin{document}

\[
\bytetable{
  C_2           & B5 6E 2C D4 F3 12 57 3E 8C 8C 1A 77 A3 EE C3 41 \\ 
  P'_3 \xor P_3 & 00 00 00 00 00 0F 00 03 00 00 00 00 00 00 00 00 \\
  C'_2          & B5 6E 2C D4 F3 1D 57 3D 8C 8C 1A 77 A3 EE C3 41 \\
}
\]

\end{document}

The \bytetable command has an optional argument for the width of the final table, default is \textwidth.

If the number of bytes is small in some instances, it should not be difficult to allow for the table to be at its natural size without manual intervention. Of course, if the number of bytes is large, there would be clashes, depending on the overall text width.

enter image description here