Skip to content

Instantly share code, notes, and snippets.

@boriscy
Last active October 29, 2015 21:36
Show Gist options
  • Save boriscy/dd0e65ed4b88db629c10 to your computer and use it in GitHub Desktop.
Save boriscy/dd0e65ed4b88db629c10 to your computer and use it in GitHub Desktop.
class CodigoControlGen
# Verhoeff Digit table variables
TABLE_D = [
[0,1,2,3,4,5,6,7,8,9],
[1,2,3,4,0,6,7,8,9,5],
[2,3,4,0,1,7,8,9,5,6],
[3,4,0,1,2,8,9,5,6,7],
[4,0,1,2,3,9,5,6,7,8],
[5,9,8,7,6,0,4,3,2,1],
[6,5,9,8,7,1,0,4,3,2],
[7,6,5,9,8,2,1,0,4,3],
[8,7,6,5,9,3,2,1,0,4],
[9,8,7,6,5,4,3,2,1,0]
].freeze
TABLE_P = [
[0,1,2,3,4,5,6,7,8,9],
[1,5,7,6,2,8,3,0,9,4],
[5,8,0,3,7,9,6,1,4,2],
[8,9,1,6,0,4,3,5,2,7],
[9,4,5,3,1,2,6,8,7,0],
[4,2,8,6,5,7,3,9,0,1],
[2,7,9,3,8,0,6,4,1,5],
[7,0,4,6,9,1,3,2,5,8]
].freeze
TABLE_INV = [0,4,3,2,1,5,6,7,8,9].freeze
DIC = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '+', '/' ].freeze
attr_accessor :autorizacion, :factura, :nitci, :fecha, :monto, :llave
def initialize(autorizacion: "", factura: "", nitci: "", fecha: "", monto: "", llave: "")
self.autorizacion = autorizacion
self.factura = factura
self.nitci = nitci
self.fecha = fecha
self.monto = monto
self.llave = llave
end
def generar
# paso 1
_autorizacion = autorizacion.dup
_factura = self.class.verhoeff_add_recursive(factura.dup, 2)
_nitci = self.class.verhoeff_add_recursive(nitci.dup, 2)
_fecha = self.class.verhoeff_add_recursive(fecha.dup, 2)
_monto = self.class.verhoeff_add_recursive(monto.dup, 2)
_suma = self.class.bcadd(self.class.bcadd(self.class.bcadd(_factura, _nitci), _fecha), _monto)
_suma = self.class.verhoeff_add_recursive(_suma, 5)
# paso2
digitos = "" << self.class.substr(_suma, -5)
digitossum = []
cadenas = []
inicio = 0
digitos.split("").each do |d|
digitossum << d.to_i + 1
cadenas << llave.slice(inicio, d.to_i + 1)# substr($llave, $inicio, $d + 1)
inicio += d.to_i + 1
end
_autorizacion << cadenas[0]
_factura << cadenas[1]
_nitci << cadenas[2]
_fecha << cadenas[3]
_monto << cadenas[4]
# paso3
str = "#{_autorizacion}#{_factura}#{_nitci}#{_fecha}#{_monto}"
arc4 = self.class.allegedrc4(str, "#{llave}#{digitos}")
# paso4
suma_total = 0;
sumas = Array.new(5, 0)
arc4.each_char.each_with_index do |chr, i|
x = chr.bytes.first
sumas[i % 5] += x
suma_total += x
end
## paso5
total = 0
sumas.each_with_index do |val, i|
total = (total + ((suma_total * val).to_i / digitossum[i]).to_i).to_i
end
_mensaje = self.class.big_base_convert(total)
res = self.class.allegedrc4(_mensaje, "#{llave}#{digitos}")
res.split("").each_slice(2).map(&:join).join('-')
end
def self.substr(str, len)
if len.abs > str.length
str
else
str.slice(len, len.abs)
end
end
def self.bcadd(a, b)
a.to_i + b.to_i
end
def self.big_base_convert(numero, base = 64)
cociente, resto = 1, 0
palabra = ""
while bccomp(cociente, 0) != 0
cociente = (numero / base).to_i # bcdiv
resto = numero % base
palabra = DIC[resto] + palabra
numero = cociente
end
palabra
end
def self.bccomp(a, b)
a, b = a.to_i, b.to_i
if a > b
1
elsif b > a
-1
else
0
end
end
def self.allegedrc4(mensaje, llaverc4)
state = []
x, y, index1, index2 = 0, 0, 0, 0
nmen = 0
strlen_llave = llaverc4.length
cifrado = ""
state = (0..255).to_a
(0..255).each do |val|
index2 = ( llaverc4[index1].bytes.first + state[val] + index2 ) % 256
state[val], state[index2] = [ state[index2], state[val] ]
index1 = (index1 + 1) % strlen_llave
end
mensaje.each_char do |chr|
x = (x + 1) % 256
y = (state[x] + y) % 256
state[x], state[y] = [state[y], state[x]]
nmen = chr.bytes.first ^ state[ ( state[x] + state[y] ) % 256]
cifrado << "0#{big_base_convert(nmen, 16)}".slice(-2, 2)
end
cifrado
end
def self.calcsum(number)
c = 0
rev = number.reverse
rev.each_char.each_with_index do |chr, ind|
c = TABLE_D[c][TABLE_P[(ind + 1) % 8][rev[ind].to_i ]]
end
TABLE_INV[c]
end
def self.verhoeff_add_recursive(number, digits)
temp = number.to_s
while (digits > 0)
temp << calcsum(temp).to_s
digits -= 1
end
temp
end
end
require 'spec_helper'
describe CodigoControlGen do
it 'a' do
cc = CodigoControlGen.new(
autorizacion:'29040011007',
factura: '1503',
nitci: '4189179011',
fecha: '20070702',
monto: '2500',
llave:'9rCB7Sv4X29d)5k7N%3ab89p-3(5[A'
)
expect(cc.generar).to eq("6A-DC-53-05-14")
end
it 'B' do
cc = CodigoControlGen.new(
autorizacion: '79040011859',
factura: '152',
nitci: '1026469026',
fecha: '20070728',
monto: '135',
llave: 'A3Fs4s$)2cvD(eY667A5C4A2rsdf53kw9654E2B23s24df35F5'
)
expect(cc.generar).to eq("FB-A6-E4-78")
end
it 'C' do
cc = CodigoControlGen.new(
autorizacion: '20040010113',
factura: '665',
nitci: '1004141023',
fecha: '20070108',
monto: '905',
llave: '442F3w5AggG7644D737asd4BH5677sasdL4%44643(3C3674F4'
)
expect(cc.generar).to eq("71-D5-61-C8")
end
it 'D' do
cc = CodigoControlGen.new(
autorizacion: '1904008691195',
factura: '978256',
nitci: '0',
fecha: '20080201',
monto: '26006',
llave: 'pPgiFS%)v}@N4W3aQqqXCEHVS2[aDw_n%3)pFyU%bEB9)YXt%xNBub4@PZ4S9)ct'
)
expect(cc.generar).to eq("62-12-AF-1B")
end
it 'E' do
cc = CodigoControlGen.new(
autorizacion: '10040010640',
factura: '9901',
nitci: '1035012010',
fecha: '20070813',
monto: '451',
llave: 'DSrCB7Ssdfv4X29d)5k7N%3ab8p3S(asFG5YU8477SWW)FDAQA'
)
expect(cc.generar).to eq("6A-50-31-01-32")
end
it 'F' do
cc = CodigoControlGen.new(
autorizacion: '30040010595',
factura: '10015',
nitci: '953387014',
fecha: '20070825',
monto: '5726',
llave: '33E265B43C4435sdTuyBVssD355FC4A6F46sdQWasdA)d56666fDsmp9846636B3'
)
expect(cc.generar).to eq("A8-6B-FD-82-16")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment