diff --git a/lib/NGCP/Panel/Controller/Device.pm b/lib/NGCP/Panel/Controller/Device.pm index 9f2ab1ddff..7b55813935 100644 --- a/lib/NGCP/Panel/Controller/Device.pm +++ b/lib/NGCP/Panel/Controller/Device.pm @@ -1424,11 +1424,26 @@ sub dev_field_config :Chained('/') :PathPart('device/autoprov/config') :Args() { $c->response->body($cipher->encrypt($processed_data)); } else { =cut - $c->response->content_type($dev->profile->config->content_type); - $c->response->body($processed_data); -=pod + my $result = $self->dev_field_encrypt( $c, $dev, $processed_data, $vars); + $c->response->content_type($result->{content_type}); + $c->response->body(${$result->{content}}); +} +sub dev_field_encrypt :Private{ + my ($self, $c, $dev, $processed_data, $vars) = @_; + + my $result = {'content' => \$processed_data }; + + my $model = $dev->profile->config->device; + + my $module = 'NGCP::Panel::Utils::Device'; + my $method = $module->can(lc($model->vendor.'_fielddev_config_process')); + if ( $method ) { + $result->{content_type} //= 'application/octet-stream'; + $method->(\$processed_data, $result, 'field_device' => $dev, 'vars' => $vars ); + }else{ + $result->{content_type} //= $dev->profile->config->content_type; } -=cut + return $result; } sub dev_field_bootstrap :Chained('/') :PathPart('device/autoprov/bootstrap') :Args() { @@ -1547,8 +1562,9 @@ sub dev_field_bootstrap :Chained('/') :PathPart('device/autoprov/bootstrap') :Ar $c->log->debug("providing config to $id"); $c->log->debug($processed_data); - $c->response->content_type($dev->profile->config->content_type); - $c->response->body($processed_data); + my $result = $self->dev_field_encrypt( $c, $dev, $processed_data, $vars); + $c->response->content_type($result->{content_type}); + $c->response->body(${$result->{content}}); } sub dev_servercert :Chained('/') :PathPart('device/autoprov/servercert') :Args(0) { @@ -1946,16 +1962,16 @@ sub dev_field_firmware_latest :Chained('dev_field_firmware_version_base') :PathP sub devices_preferences_list :Chained('devmod_base') :PathPart('preferences') :CaptureArgs(0) { my ($self, $c) = @_; - + my $dev_pref_rs = NGCP::Panel::Utils::Preferences::get_preferences_rs( c => $c, type => 'dev', id => $c->stash->{devmod}->id, ); - + my $pref_values = get_inflated_columns_all($dev_pref_rs,'hash' => 'attribute', 'column' => 'value', 'force_array' => 1); - NGCP::Panel::Utils::Preferences::load_preference_list( + NGCP::Panel::Utils::Preferences::load_preference_list( c => $c, pref_values => $pref_values, dev_pref => 1, @@ -2007,7 +2023,7 @@ sub devices_preferences_edit :Chained('devices_preferences_base') :PathPart('edi ->all; my $pref_rs = $c->stash->{devmod}->voip_dev_preferences; - NGCP::Panel::Utils::Preferences::create_preference_form( + NGCP::Panel::Utils::Preferences::create_preference_form( c => $c, pref_rs => $pref_rs, enums => \@enums, @@ -2027,7 +2043,7 @@ sub profile_preferences_list :Chained('devprof_base') :PathPart('preferences') : ); my $pref_values = get_inflated_columns_all($devprof_pref_rs,'hash' => 'attribute', 'column' => 'value', 'force_array' => 1); - NGCP::Panel::Utils::Preferences::load_preference_list( + NGCP::Panel::Utils::Preferences::load_preference_list( c => $c, pref_values => $pref_values, 'devprof_pref' => 1, @@ -2079,7 +2095,7 @@ sub profile_preferences_edit :Chained('profile_preferences_base') :PathPart('edi ->all; my $pref_rs = $c->stash->{devprof}->voip_devprof_preferences; - NGCP::Panel::Utils::Preferences::create_preference_form( + NGCP::Panel::Utils::Preferences::create_preference_form( c => $c, pref_rs => $pref_rs, enums => \@enums, diff --git a/lib/NGCP/Panel/Utils/Device.pm b/lib/NGCP/Panel/Utils/Device.pm index 2c111ee0e6..1174730054 100644 --- a/lib/NGCP/Panel/Utils/Device.pm +++ b/lib/NGCP/Panel/Utils/Device.pm @@ -1,7 +1,13 @@ package NGCP::Panel::Utils::Device; - use strict; +use warnings; +use Crypt::Rijndael; +use Digest::SHA qw/sha256/; +use IO::String; + +our $denwaip_masterkey = '@newrocktech2007'; +our $denwaip_magic_head = "\x40\x40\x40\x24\x24\x40\x40\x40\x40\x40\x40\x24\x24\x40\x40\x40"; sub process_connectable_models{ my ($c, $just_created, $devmod, $connectable_models_in) = @_; @@ -26,7 +32,7 @@ sub process_connectable_models{ }else{ push @$connectable_models_ids, $name_or_id; } - } + } my @columns = ('device_id' , 'extension_id'); if('extension' eq $devmod->type){ #extension can be connected to other extensions? If I remember right - yes. @@ -54,11 +60,148 @@ sub process_connectable_models{ $schema->resultset('autoprov_device_extensions')->create({ $columns[0] => $devmod->id, $columns[1] => $connected_id, - }); + }); } } } +sub denwaip_fielddev_config_process{ + my($config, $result, %params) = @_; + my $field_device = $params{field_device}; + $result->{content} = denwaip_encrypt(${$result->{content}}, $field_device->identifier ); +} + +sub denwaip_encrypt{ + my ($plain, $mac) = @_; + + my $encrypted_data = IO::String->new(); + + $mac = lc($mac); + + # hard coded master key + my $key = $mac . $denwaip_masterkey; + + # file starts with a hard coded magic + print $encrypted_data ($denwaip_magic_head); + + # generate random seed. originally SHA hash over input file path+name plus some other unknown value + my $seed = sha256(rand() . rand() . rand()); + $seed = substr($seed, 0, 16); + print $encrypted_data ($seed); + + # 256 iterations of sha256 + my $keybuf = $seed . ("\0" x 16); + for (1 .. 256) { + my $hash = sha256($keybuf . $key); + $keybuf = $hash; + } + + # got our AES key + my $cipher = Crypt::Rijndael->new($keybuf, Crypt::Rijndael::MODE_ECB()); + + # for final checksum + my $xor1 = (chr(54) x 64); + my $xor2 = (chr(92) x 64); + + substr($xor1, 0, 32) = substr($xor1, 0, 32) ^ substr($keybuf, 0, 32); + substr($xor2, 0, 32) = substr($xor2, 0, 32) ^ substr($keybuf, 0, 32); + + # initialize checksum SHA context + my $checksum_sha = Digest::SHA->new('sha256'); + $checksum_sha->add($xor1); + + # encrypt routine + while ($plain ne '') { + # each plaintext block is xor'd with the current "seed", then run through AES, then written to file + + my $plain_block = substr($plain, 0, 16, ''); + + # pad block to 16 bytes. original code seems to leave contents of previous buffer unchanged + # if block is smaller than 16 bytes -- unsure if this is a requirement + while (length($plain_block) < 16) { + $plain_block .= "\0"; + } + + substr($plain_block, 0, 16) = substr($plain_block, 0, 16) ^ substr($seed, 0, 16); + + my $enc_block = $cipher->encrypt($plain_block); + print $encrypted_data ($enc_block); + + $checksum_sha->add($enc_block); + # "seed" for the next block is the previous encrypted block + $seed = $enc_block; + } + + my $interim_sha = $checksum_sha->digest(); + my $checksum = sha256($xor2 . $interim_sha); + print $encrypted_data ($checksum); + + return $encrypted_data->string_ref; +} + +=pod +sub denwaip_decrypt{ + my ($crypted, $mac) = @_; + + my $plain_data = IO::String->new(); + + $mac = lc($mac); + + # hard coded master key + my $key = $mac . $denwaip_masterkey; + + # file starts with a hard coded magic + my $magic = substr($crypted, 0, 16, ''); + $denwaip_magic_head eq "\x40\x40\x40\x24\x24\x40\x40\x40\x40\x40\x40\x24\x24\x40\x40\x40" or die "Wrong denwaip crypted data format."; + + # "random" seed taken from file + my $seed = substr($crypted, 0, 16, ''); + + # 256 iterations of sha256 + my $keybuf = $seed . ("\0" x 16); + for (1 .. 256) { + my $hash = sha256($keybuf . $key); + $keybuf = $hash; + } + + # got our AES key + my $cipher = Crypt::Rijndael->new($keybuf, Crypt::Rijndael::MODE_ECB()); + + # for final checksum + my $xor1 = (chr(54) x 64); + my $xor2 = (chr(92) x 64); + + substr($xor1, 0, 32) = substr($xor1, 0, 32) ^ substr($keybuf, 0, 32); + substr($xor2, 0, 32) = substr($xor2, 0, 32) ^ substr($keybuf, 0, 32); + + # remove trailing checksum from buffer + my $final_checksum = substr($crypted, -32, 32, ''); + + # initialize checksum SHA context + my $checksum_sha = Digest::SHA->new('sha256'); + $checksum_sha->add($xor1); + + # decrypt routine + while ($crypted ne '') { + # each plaintext block is xor'd with the current "seed", then run through AES, then written to file + + my $block = substr($crypted, 0, 16, ''); + $checksum_sha->add($block); + + my $dec_block = $cipher->decrypt($block); + substr($dec_block, 0, 16) = substr($dec_block, 0, 16) ^ substr($seed, 0, 16); + print $plain_data ($dec_block); + + # "seed" for the next block is the previous encrypted block + $seed = $block; + } + + my $interim_sha = $checksum_sha->digest(); + my $checksum = sha256($xor2 . $interim_sha); + $final_checksum eq $checksum or die "Denwaip checksum failed."; + return $plain_data->string_ref; +} +=cut 1; =head1 NAME