diff --git a/.gitignore b/.gitignore index 900ae88..4c40c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /Gemfile.lock /vendor .env +/ext/Makefile *.DS_Store *.sw[po] diff --git a/Gemfile b/Gemfile index d4781a3..f90dfa5 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ ruby RUBY_VERSION gemspec -gem "rake", "~> 12.3" +gem "rake", "~> 13" gem "rspec", "~> 3.5" gem "pry" @@ -36,3 +36,8 @@ else end end + +gem "jruby-openssl", "~> 0.14", platform: :jruby +gem "ruby-prof" +gem "rake-compiler" +gem "benchmark-ips" \ No newline at end of file diff --git a/Rakefile b/Rakefile index 59b9069..02fea3e 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,9 @@ # frozen_string_literal: true require "bundler/gem_tasks" +require 'rake/extensiontask' + +Rake::ExtensionTask.new('netsnmp_ext') begin require "rspec/core/rake_task" diff --git a/ext/netsnmp_ext/extconf.rb b/ext/netsnmp_ext/extconf.rb new file mode 100644 index 0000000..7dd759e --- /dev/null +++ b/ext/netsnmp_ext/extconf.rb @@ -0,0 +1,2 @@ +require 'mkmf' +create_makefile 'netsnmp_ext' \ No newline at end of file diff --git a/ext/netsnmp_ext/netsnmp_ext.c b/ext/netsnmp_ext/netsnmp_ext.c new file mode 100644 index 0000000..fc933e9 --- /dev/null +++ b/ext/netsnmp_ext/netsnmp_ext.c @@ -0,0 +1,46 @@ +#include + +#define USM_LENGTH_EXPANDED_PASSPHRASE (1024 * 1024) /* 1Meg. */ +#define USM_LENGTH_KU_HASHBLOCK 64 + +static VALUE mNETSNMP; +static VALUE cNETSNMP_Sec_Params; + +static VALUE NETSNMP_expand_passphrase(VALUE self, VALUE password) +{ + char *P; + size_t P_len; + int nbytes = USM_LENGTH_EXPANDED_PASSPHRASE; + u_int pindex = 0; + u_char buf[USM_LENGTH_EXPANDED_PASSPHRASE], *bufp; + + StringValue(password); + P = RSTRING_PTR(password); + P_len = RSTRING_LEN(password); + + bufp = buf; + while (nbytes > 0) { + *bufp++ = P[pindex++ % P_len]; + // if (!EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK)) + // ossl_raise(eDigestError, "EVP_DigestUpdate"); + + nbytes--; + } + + // if (!EVP_DigestFinal_ex(ctx, &Ku, &kulen)) + // ossl_raise(eDigestError, "EVP_DigestFinal_ex"); + + // memset(buf, 0, sizeof(buf)); + + // TODO: trim to 16 bytes if auth protocol is md5 + + return rb_usascii_str_new((const char *) buf, USM_LENGTH_EXPANDED_PASSPHRASE); +} + +void Init_netsnmp_ext( void ) +{ + mNETSNMP = rb_define_module("NETSNMP"); + cNETSNMP_Sec_Params = rb_define_class_under(mNETSNMP, "SecurityParameters", rb_cObject); + // rb_define_method(cNETSNMP_Sec_Params, "passkey", NETSNMP_passkey, 1); + rb_define_method(cNETSNMP_Sec_Params, "expand_passphrase", NETSNMP_expand_passphrase, 1); +} \ No newline at end of file diff --git a/lib/netsnmp.rb b/lib/netsnmp.rb index 02787d5..f9232a2 100644 --- a/lib/netsnmp.rb +++ b/lib/netsnmp.rb @@ -51,6 +51,7 @@ def xor(other) require "netsnmp/message" require "netsnmp/encryption/des" require "netsnmp/encryption/aes" +require "netsnmp_ext" if RUBY_ENGINE == "ruby" require "netsnmp/client" diff --git a/lib/netsnmp/security_parameters.rb b/lib/netsnmp/security_parameters.rb index 43fa655..bf62f33 100644 --- a/lib/netsnmp/security_parameters.rb +++ b/lib/netsnmp/security_parameters.rb @@ -191,22 +191,24 @@ def localize_key(key) def passkey(password) digest.reset - password_index = 0 + digest << expand_passphrase(password) + + dig = digest.digest + dig = dig[0, 16] if @auth_protocol == :md5 + dig || "" + end - # buffer = +"" + def expand_passphrase(password) + password_index = 0 + buffer = "".b password_length = password.length while password_index < 1048576 initial = password_index % password_length - rotated = String(password[initial..-1]) + String(password[0, initial]) - buffer = (rotated * (64 / rotated.length)) + String(rotated[0, 64 % rotated.length]) + rotated = String(password.byteslice(initial..-1)) + String(password.byteslice(0, initial)) + buffer << (rotated * (64 / rotated.length)) + String(rotated.byteslice(0, 64 % rotated.length)) password_index += 64 - digest << buffer - buffer.clear end - - dig = digest.digest - dig = dig[0, 16] if @auth_protocol == :md5 - dig || "" + buffer end def digest diff --git a/netsnmp.gemspec b/netsnmp.gemspec index b77bec8..497bf73 100644 --- a/netsnmp.gemspec +++ b/netsnmp.gemspec @@ -21,6 +21,9 @@ Gem::Specification.new do |gem| # Manifest gem.files = Dir["LICENSE.txt", "README.md", "AUTHORS", "lib/**/*.rb", "sig/**/*.rbs"] gem.require_paths = ["lib"] + if RUBY_ENGINE == "ruby" + gem.extensions = ["ext/extconf.rb"] + end gem.add_runtime_dependency "parslet" gem.metadata["rubygems_mfa_required"] = "true" diff --git a/spec/support/specs.sh b/spec/support/specs.sh index b859feb..97bc37b 100755 --- a/spec/support/specs.sh +++ b/spec/support/specs.sh @@ -23,6 +23,24 @@ cd /home bundle -v bundle install +cat <> /etc/ssl/openssl.cnf + +[provider_sect] +default = default_sect +legacy = legacy_sect + +[default_sect] +activate = 1 + +[legacy_sect] +activate = 1 + +EOT + +if [[ "$RUBY_ENGINE" = "ruby" ]]; then + bundle exec rake compile +fi + if [[ ${RUBY_VERSION:0:1} = "3" ]]; then export RUBYOPT='-rbundler/setup -rrbs/test/setup' export RBS_TEST_RAISE=true